UNPKG

21.5 kBTypeScriptView Raw
1import * as exp from "express";
2import { HandleCommand } from "./HandleCommand";
3import { HandleEvent } from "./HandleEvent";
4import { ExpressServerOptions } from "./internal/transport/express/ExpressServer";
5import { AutomationEventListener } from "./server/AutomationEventListener";
6import { AutomationMetadataProcessor } from "./spi/env/MetadataProcessor";
7import { SecretResolver } from "./spi/env/SecretResolver";
8import { GraphClientFactory } from "./spi/graph/GraphClientFactory";
9import { HttpClientFactory } from "./spi/http/httpClient";
10import { WebSocketFactory } from "./spi/http/wsClient";
11import { StatsDClientFactory } from "./spi/statsd/statsdClient";
12import { Maker } from "./util/constructionUtils";
13/**
14 * Customize the express server configuration: For example to add custom routes
15 *
16 * Example:
17 *
18 * const newRouteCustomizer = (express: exp.Express, ...handlers: exp.RequestHandler[]) => {
19 * express.get("/new-route", ...handlers, (req, res) => {
20 * res.json({ key: "value" });
21 * });
22 * }
23 */
24export declare type ExpressCustomizer = (express: exp.Express, ...handlers: exp.RequestHandler[]) => void;
25/**
26 * Post process the configuration after is has been merged from the various locations, but
27 * before starting the automation client.
28 */
29export declare type ConfigurationPostProcessor<T = AnyOptions> = (configuration: Configuration) => Promise<Configuration & T>;
30/**
31 * A computed banner
32 */
33export interface Banner {
34 /**
35 * Banner content
36 */
37 banner: string;
38 /**
39 * Whether or not the banner content should be asciified
40 */
41 asciify: boolean;
42 color: "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray";
43}
44/**
45 * A section that should be displayed in the banner.
46 */
47export interface BannerSection {
48 title: string;
49 body: string;
50}
51/**
52 * Custom configuration you can abuse to your benefit
53 */
54export interface AnyOptions {
55 /** Abuse goes here */
56 [key: string]: any;
57}
58/**
59 * Options for an automation node.
60 */
61export interface AutomationOptions extends AnyOptions {
62 /**
63 * Automation name. If not given, the name is extracted from
64 * the package.json.
65 */
66 name?: string;
67 /**
68 * Automation version. Must be a valid semantic version,
69 * https://semver.org/. If not given, the version is extracted
70 * from the package.json.
71 */
72 version?: string;
73 /**
74 * Atomist workspaces this automation will be registered with. Must be
75 * specified if groups is not specified. Cannot be specified if
76 * groups is specified.
77 */
78 workspaceIds?: string[];
79 /**
80 * DO NOT USE. Groups this automation will be registered with.
81 * Must be specified if teams is not specified. Cannot be
82 * specified if teams is specified. Providing groups indicates
83 * this is a global automation, which can only successfully be
84 * registered by Atomist.
85 */
86 groups?: string[];
87 /**
88 * If events should be queued when the registration is not
89 * connected to the websocket, specificy "durable". "ephemeral"
90 * is suited for testing and running locally and is the default.
91 */
92 policy?: "ephemeral" | "durable";
93 /**
94 * Atomist API Key used to authenticate the user starting the client.
95 */
96 apiKey?: string;
97 /** HTTP configuration, useful for health checks */
98 http?: {
99 enabled?: boolean;
100 client?: {
101 factory?: HttpClientFactory;
102 };
103 } & Partial<ExpressServerOptions>;
104 /** websocket configuration */
105 ws?: {
106 enabled?: boolean;
107 client?: {
108 factory?: WebSocketFactory;
109 };
110 termination?: {
111 /**
112 * If true, wait for up to `gracePeriod` milliseconds to
113 * process in-flight and queued requests.
114 */
115 graceful?: boolean;
116 /**
117 * Grace period in milliseconds. Note the actual time to
118 * shutdown gracefully may be more than twice this, as
119 * this period is used to first wait for requests and then
120 * used again to wait for any cluster workers to shutdown.
121 * If some part of the shutdown hangs, it could take up to
122 * ten times this period for all processes to exit.
123 */
124 gracePeriod?: number;
125 };
126 /** compress messages over websocket */
127 compress?: boolean;
128 /** timeout in milliseconds */
129 timeout?: number;
130 /** Configure backoff behavior on the WS connection */
131 backoff?: {
132 /**
133 * Max number of the pending messages in the queue before
134 * initiating backoff
135 */
136 threshold?: number;
137 /** Interval in ms to check threshold */
138 interval?: number;
139 /**
140 * Duration in ms the backend should backoff before sending
141 * any more messages
142 */
143 duration?: number;
144 /**
145 * Factor (0 < x <= 1) multiply threshold to get to the lower backoff
146 * boundary
147 */
148 factor?: number;
149 };
150 };
151 graphql?: {
152 client?: {
153 factory: GraphClientFactory;
154 };
155 };
156 /** Atomist API endpoints */
157 endpoints?: {
158 graphql?: string;
159 api?: string;
160 auth?: string;
161 };
162 /**
163 * Post-processors can be used to modify the configuration after
164 * all standard configuration loading has been done and before the
165 * client is started. Post-processors return a configuration
166 * promise so they can be asynchronous.
167 */
168 postProcessors?: ConfigurationPostProcessor[];
169}
170/**
171 * Options useful when running an automation client in server mode.
172 */
173export interface AutomationServerOptions extends AutomationOptions {
174 /** environment automation is running in, e.g., "production" or "testing" */
175 environment?: string;
176 /**
177 * Application identifier used for metrics send to statsd. If not
178 * set, the automation client package name with any namespace
179 * prefix removed is used.
180 */
181 application?: string;
182 /** keywords useful for discovery */
183 keywords?: string[];
184 /** Whether and where to send application start and stop events to Atomist. */
185 applicationEvents?: {
186 enabled?: boolean;
187 workspaceId?: string;
188 };
189 /**
190 * Whether and how many workers to start up. If enabled is true
191 * and workers is false, a number of workers equal to the number
192 * of available CPUs will be started.
193 */
194 cluster?: {
195 enabled?: boolean;
196 workers?: number;
197 maxConcurrentPerWorker?: number;
198 };
199 /** Logging configuration */
200 logging?: {
201 /** Log level, default is "info" */
202 level?: "silly" | "debug" | "verbose" | "info" | "warn" | "error";
203 /**
204 * Custom log configuration, useful if your logging solution
205 * requires host, port, token, etc. configuration.
206 */
207 custom?: any;
208 /**
209 * Print welcome banner; set to an arbitrary string to display,
210 * default is name of automation-client
211 */
212 banner?: {
213 enabled?: boolean;
214 /** Message or Banner to be printed at the top of the banner */
215 message?: string | ((configuration: Configuration) => Banner);
216 /**
217 * Add content to the banner which shows up between handlers and
218 * footer
219 */
220 contributors?: Array<(configuration: Configuration) => string | BannerSection>;
221 };
222 /**
223 * Log to file; set to file path to overwrite location and name of logfile,
224 * defaults to ./log/automation-client.log in current working directory
225 */
226 file?: {
227 enabled?: boolean;
228 name?: string;
229 level?: "silly" | "debug" | "verbose" | "info" | "warn" | "error";
230 };
231 };
232 /** Redaction configuration */
233 redact?: {
234 /** Redact log messages */
235 log?: boolean;
236 /** Redact messages send via the message client */
237 messages?: boolean;
238 /** Register patterns to look for and optional replacements */
239 patterns?: Array<{
240 regexp: RegExp | string;
241 replacement?: string;
242 }>;
243 };
244 /** statsd config */
245 statsd?: {
246 /** Whether to send metrics statsd, default is false */
247 enabled?: boolean;
248 /**
249 * statsd host. If not set, use the host-shots default,
250 * "localhost" at the time of this writing.
251 */
252 host?: string;
253 /**
254 * statsd port. If not set, use the hot-shots default, 8125
255 * at the time of this writing.
256 */
257 port?: number;
258 /**
259 * statsd client factory to create instances of StatsDClient
260 */
261 client?: {
262 factory: StatsDClientFactory;
263 };
264 };
265 /** Register a custom secret resolver */
266 secretResolver?: SecretResolver;
267 /** Register a custom AutomationMetadataProcessor */
268 metadataProcessor?: AutomationMetadataProcessor;
269}
270/**
271 * Atomist automation configuration.
272 */
273export interface Configuration extends AutomationServerOptions {
274 /**
275 * Automation commands this package provides. If empty or null,
276 * the package will be scanned for commands, which must be under a
277 * directory named "commands".
278 */
279 commands?: Array<Maker<HandleCommand>>;
280 /**
281 * Automation event handlers this package provides. If empty or
282 * null, the package will be scanned for event handlers, which
283 * must be under a directory named "events".
284 */
285 events?: Array<Maker<HandleEvent>>;
286 /** Custom event ingester */
287 ingesters?: string[];
288 /** Log and metric sinks */
289 listeners?: AutomationEventListener[];
290}
291/**
292 * User per-automation configuration
293 */
294export interface ModuleOptions extends AutomationServerOptions {
295 /** Automation name this configuration applies to. */
296 name: string;
297 /**
298 * A valid version or version range, as defined by
299 * https://www.npmjs.com/package/semver, this configuration
300 * applies to. If not provided, it applies to all versions of the
301 * named automation.
302 */
303 version?: string;
304}
305/**
306 * User-wide configuration and user per-automation configuration
307 */
308export interface UserConfig extends AutomationServerOptions {
309 modules?: ModuleOptions[];
310}
311/**
312 * Generate defaults for various configuration option values. These
313 * will only be used if values are not provided by any source. Values
314 * not provided here will be `undefined`.
315 *
316 * @return default configuration
317 */
318export declare function defaultConfiguration(): Configuration;
319/**
320 * Exposes the configuration for lookup of configuration values.
321 * This is useful for components to obtain values eg. from configuration.custom
322 * like user provided secrets etc.
323 * @param {string} path the property path evaluated against the configuration instance
324 * @returns {T}
325 */
326export declare function configurationValue<T>(path?: string, defaultValue?: T): T;
327/**
328 * Return user automation client configuration path.
329 */
330export declare function userConfigPath(): string;
331/**
332 * Return user automation client configuration paths including
333 * such referenced by configuration profiles.
334 */
335export declare function userConfigPaths(): string[];
336/**
337 * Write user config securely, creating directories as necessary.
338 */
339export declare function writeUserConfig(cfg: UserConfig): Promise<void>;
340/**
341 * Read and return user config from UserConfigFile.
342 */
343export declare function getUserConfig(): UserConfig;
344/**
345 * Overwrite values in the former configuration with values in the
346 * latter. The start object is modified.
347 *
348 * @param obj starting configuration
349 * @param override configuration values to add/override those in start
350 * @return resulting merged configuration
351 */
352export declare function mergeConfigs(obj: Configuration, ...sources: Configuration[]): Configuration;
353/**
354 * Overwrite values in the former configuration with values in the
355 * latter. The start object is modified. Arrays are concatenated.
356 *
357 * @param obj starting configuration
358 * @param override configuration values to add/override those in start
359 * @return resulting merged configuration
360 */
361export declare function deepMergeConfigs(obj: Configuration, ...sources: Configuration[]): Configuration;
362/**
363 * Merge a user's global and proper per-module configuration, if it
364 * exists. Values from the per-module configuration take precedence
365 * over the user-wide values. Per-module configuration is gotten from
366 * the first per-module configuration that matches name and,
367 * optionally, the version is within the per-module configuration's
368 * version range. A module configuration without a version range
369 * matches the named module with any version. If no version is
370 * provided, any version range is satisfied, meaning the first
371 * per-module configuration with a matching name is used. If no name
372 * is provide, only the user configuration is loaded. The first
373 * per-module match is used. This means if you have multiple
374 * configurations for the same named module and you want to include a
375 * default configuration for that module, put a configuration without
376 * a version range _after_ all the configurations with version ranges.
377 * Note that only values from the first per-module match are used.
378 *
379 * @param userConfig the user's configuration, which may include per-module configuration
380 * @param name automation client package name to load as module config if it exists
381 * @param version automation client package version to load as module config if
382 * version satifies module config version range
383 * @return the merged module and user configuration
384 */
385export declare function resolveModuleConfig(userConfig: UserConfig, name?: string, version?: string): AutomationServerOptions;
386/**
387 * Try to read user config, overriding its values with a per-module
388 * configuration that matches this automation.
389 *
390 * @param name automation client package name to load as module config if it exists
391 * @param version automation client package version to load as module config if
392 * version satifies module config version range
393 * @return module-specific config with user config supplying defaults
394 */
395export declare function loadUserConfiguration(name?: string, version?: string): AutomationServerOptions;
396/**
397 * Load the automation configuration from the configuration object
398 * exported from cfgPath and return it. If no configuration path is
399 * provided, the package will be searched for a file named
400 * atomist.config.js. If no atomist.config.js is found, an empty
401 * object is returned. If more than one is found, an exception is
402 * thrown.
403 *
404 * @param cfgPath location of automation configuration
405 * @return automation configuration or undefined
406 */
407export declare function loadAutomationConfig(configPath?: string): Promise<Configuration | undefined>;
408/**
409 * Load the automation configuration from the configuration objects
410 * exported and merged by all index.js files in the automation client.
411 *
412 * @return automation configuration
413 */
414export declare function loadIndexConfig(): Promise<Configuration>;
415/**
416 * Load configuration from the file defined by the ATOMIST_CONFIG_PATH
417 * environment variable, if it the variable is defined and the file
418 * exists, and return it. The contents of the ATOMIST_CONFIG_PATH
419 * file should be serialized JSON of AutomationServerOptions. If the
420 * environment variable is not defined or the file path specified by
421 * its value cannot be read as JSON, an empty object is returned.
422 *
423 * @return automation server options
424 */
425export declare function loadAtomistConfigPath(): AutomationServerOptions;
426/**
427 * Load configuration from the ATOMIST_CONFIG environment variable, if
428 * it the variable is defined, and merge it into the passed in
429 * configuration. The value of the ATOMIST_CONFIG environment
430 * variable should be serialized JSON of AutomationServerOptions. The
431 * values from the environment variable will override values in the
432 * passed in configuration. If the environment variable is not
433 * defined, the passed in configuration is returned unchanged.
434 *
435 * @return automation server options
436 */
437export declare function loadAtomistConfig(): AutomationServerOptions;
438/**
439 * Examine environment, config, and cfg for Atomist workspace IDs.
440 * The ATOMIST_WORKSPACES environment variable takes precedence over
441 * the config "workspaceIds", which takes precedence over
442 * cfg.workspaceId, which may be undefined, null, or an empty array.
443 *
444 * @param cfg current configuration, whose workspaceIds
445 * properties may be modified by this function
446 * @return the resolved workspace IDs
447 */
448export declare function resolveWorkspaceIds(cfg: Configuration): string[];
449/**
450 * Resolve the HTTP port from the environment and configuration. The
451 * PORT environment variable takes precedence over the config value.
452 */
453export declare function resolvePort(cfg: Configuration): number;
454/**
455 * Resolve ATOMIST_ environment variables and add them to config.
456 * Variables of like ATOMIST_custom_foo_bar will be converted to
457 * a json path of custom.foo.bar.
458 * @param {Configuration} cfg
459 */
460export declare function resolveEnvironmentVariables(cfg: Configuration): void;
461/**
462 * Resolve placeholders against the process.env.
463 * Placeholders should be of form ${ENV_VAR}. Placeholders support default values
464 * in case they aren't defined: ${ENV_VAR:default value}
465 */
466export declare function resolvePlaceholders(cfg: Configuration, replacer?: (value: string) => Promise<string>): Promise<void>;
467/**
468 * Invoke postProcessors on the provided configuration.
469 */
470export declare function invokePostProcessors(cfg: Configuration): Promise<Configuration>;
471/**
472 * Make sure final configuration has the minimum configuration it
473 * needs. It will throw an error if required properties are missing.
474 *
475 * @param cfg final configuration
476 */
477export declare function validateConfiguration(cfg: Configuration): void;
478/**
479 * Load and populate the automation configuration. The configuration
480 * is loaded from several locations with the following precedence from
481 * highest to lowest.
482 *
483 * 1. `ATOMIST_` environment variables, see [[resolveEnvironmentVariables]]
484 * 2. Configuration returned from the post-processors.
485 * 3. Recognized environment variables, see [[resolveWorkspaceIds]],
486 * [[resolvePort]]
487 * 4. The value of the ATOMIST_CONFIG environment variable, parsed as
488 * JSON and cast to AutomationServerOptions
489 * 5. The contents of the ATOMIST_CONFIG_PATH file as AutomationServerOptions
490 * 6. The contents of the user's client.config.json as UserConfig
491 * resolving user and per-module configuration into Configuration
492 * 7. The automation atomist.config.js or _all_ index.js files'
493 * configurations exported as `configuration` from those files
494 * 8. ProductionDefaultConfiguration if ATOMIST_ENV or NODE_ENV is set
495 * to "production" or TestingDefaultConfiguration if ATOMIST_ENV or
496 * NODE_ENV is set to "staging" or "testing", with ATOMIST_ENV
497 * taking precedence over NODE_ENV.
498 * 9. LocalDefaultConfiguration
499 *
500 * If any of the sources are missing, they are ignored. Any truthy
501 * configuration values specified by sources of higher precedence
502 * cause any values provided by sources of lower precedence to be
503 * ignored. Arrays are replaced, not merged. Typically the only
504 * required values in the configuration for a successful registration
505 * are the apiKey and non-empty workspaceIds.
506 *
507 * Placeholder of the form `${ENV_VARIABLE}` in string configuration
508 * values will get resolved against the environment. The resolution
509 * happens after all of the above configuration sources have been
510 * merged.
511 *
512 * After all sources are merged and the resulting configuration
513 * processed for placeholders and environment variables, the
514 * configuration is validated using [[validateConfiguration]].
515 *
516 * The configuration exported from the index.js (or atomist.config.js)
517 * is modified to contain the final configuration values and returned
518 * from this function.
519 *
520 * @param cfgPath path to file exporting the configuration object, if
521 * not provided the package is searched for one
522 * @return merged configuration object
523 */
524export declare function loadConfiguration(cfgPath?: string): Promise<Configuration>;
525/**
526 * Default set of regular expressions used to remove sensitive
527 * information from messages and logs. The entries are applied in
528 * order, so more specific regular expressions should be placed
529 * earlier in the list to avoid a shorter replacement preventing a
530 * longer replacement from being applied.
531 */
532export declare const DEFAULT_REDACTION_PATTERNS: {
533 regexp: RegExp;
534 replacement: string;
535}[];
536/**
537 * Default configuration when running in neither testing or
538 * production.
539 */
540export declare const LocalDefaultConfiguration: Configuration;
541/**
542 * Configuration defaults for production environments.
543 */
544export declare const ProductionDefaultConfiguration: Partial<Configuration>;
545/**
546 * Configuration defaults for pre-production environments.
547 */
548export declare const TestingDefaultConfiguration: Partial<Configuration>;
549//# sourceMappingURL=configuration.d.ts.map
\No newline at end of file