UNPKG

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