import * as exp from "express"; import { HandleCommand } from "./HandleCommand"; import { HandleEvent } from "./HandleEvent"; import { Ingester, IngesterBuilder } from "./ingesters"; import { ExpressServerOptions } from "./internal/transport/express/ExpressServer"; import { AutomationEventListener } from "./server/AutomationEventListener"; import { AutomationMetadataProcessor } from "./spi/env/MetadataProcessor"; import { SecretResolver } from "./spi/env/SecretResolver"; import { HttpClientFactory } from "./spi/http/httpClient"; import { Maker } from "./util/constructionUtils"; /** * Customize the express server configuration: For example to add custom routes * * Example: * * const newRouteCustomizer = (express: exp.Express, ...handlers: exp.RequestHandler[]) => { * express.get("/new-route", ...handlers, (req, res) => { * res.json({ key: "value" }); * }); * } */ export declare type ExpressCustomizer = (express: exp.Express, ...handlers: exp.RequestHandler[]) => void; /** * A computed banner */ export interface Banner { /** * Banner content */ banner: string; /** * Whether or not the banner content should be asciified */ asciify: boolean; color: "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray"; } /** * A section that should be displayed in the banner. */ export interface BannerSection { title: string; body: string; } /** * Custom configuration you can abuse to your benefit */ export interface AnyOptions { /** Abuse goes here */ [key: string]: any; } /** * Options for an automation node. */ export interface AutomationOptions extends AnyOptions { /** * Automation name. If not given, the name is extracted from * the package.json. */ name?: string; /** * Automation version. Must be a valid semantic version, * https://semver.org/. If not given, the version is extracted * from the package.json. */ version?: string; /** * Atomist teams this automation will be registered with. Must be * specified if groups is not specified. Cannot be specified if * groups is specified. * @deprecated The usage of teamIds is deprecated and will be removed * in a future release. Please use workspaceIds instead. */ teamIds?: string[]; /** * Atomist workspaces this automation will be registered with. Must be * specified if groups is not specified. Cannot be specified if * groups is specified. */ workspaceIds?: string[]; /** * DO NOT USE. Groups this automation will be registered with. * Must be specified if teams is not specified. Cannot be * specified if teams is specified. Providing groups indicates * this is a global automation, which can only successfully be * registered by Atomist. */ groups?: string[]; /** * If events should be queued when the registration is not * connected to the websocket, specificy "durable". "ephemeral" * is suited for testing and running locally and is the default. */ policy?: "ephemeral" | "durable"; /** * GitHub personal access token with, at minimum, read:org scope. * The GitHub user that owns this token must be associated with an * Atomist person with the developer role. Additional scopes may * be necessary if the automation uses the token to perform * actions against the GitHub API. * @deprecated The usage of tokens is deprecated and will be removed in * a future release. Please use apiKey instead. */ token?: string; /** * Atomist API Key used to authenticate the user starting the client. * If apiKey is specified it will be used over a provided token. */ apiKey?: string; /** HTTP configuration, useful for health checks */ http?: { enabled?: boolean; client?: { factory?: HttpClientFactory; }; } & Partial; /** websocket configuration */ ws?: { enabled?: boolean; termination?: { /** * if true, give in-flight transactions `gracePeriod` * milliseconds to complete when shutting down */ graceful?: boolean; /** grace period in millisends */ gracePeriod?: number; }; /** compress messages over websocket */ compress?: boolean; /** timeout in milliseconds */ timeout?: number; }; /** Atomist API endpoints */ endpoints?: { graphql?: string; api?: string; }; /** * Post-processors can be used to modify the configuration after * all standard configuration loading has been done and before the * client is started. Post-processors return a configuration * promise so they can be asynchronous. */ postProcessors?: Array<(configuration: Configuration) => Promise>; } /** * Options useful when running an automation client in server mode. */ export interface AutomationServerOptions extends AutomationOptions { /** environment automation is running in, e.g., "production" or "testing" */ environment?: string; /** * Application identifier used for metrics send to statsd. If not * set, the automation client package name with any namespace * prefix removed is used. */ application?: string; /** keywords useful for discovery */ keywords?: string[]; /** Whether and where to send application start and stop events to Atomist. */ applicationEvents?: { enabled?: boolean; /** * @deprecated teamId is deprecated and will be removed in a future release. * Use workspaceId instead. */ teamId?: string; workspaceId?: string; }; /** * Whether and how many workers to start up. If enabled is true * and workers is false, a number of workers equal to the number * of available CPUs will be started. */ cluster?: { enabled?: boolean; workers?: number; }; /** Logging configuration */ logging?: { /** Log level, default is "info" */ level?: "debug" | "info" | "warn" | "error"; /** * Custom log configuration, useful if your logging solution * requires host, port, token, etc. configuration. */ custom?: any; /** * Print welcome banner; set to an arbitrary string to display, * default is name of automation-client */ banner?: { enabled?: boolean; /** Message or Banner to be printed at the top of the banner */ message?: string | ((configuration: Configuration) => Banner); /** * Add content to the banner which shows up between handlers and * footer */ contributors?: Array<(configuration: Configuration) => string | BannerSection>; }; /** * Log to file; set to file path to overwrite location and name of logfile, * defaults to ./log/automation-client.log in current working directory */ file?: { enabled?: boolean; name?: string; level?: string; }; }; /** statsd config */ statsd?: { /** Whether to send metrics statsd, default is false */ enabled?: boolean; /** * statsd host. If not set, use the host-shots default, * "localhost" at the time of this writing. */ host?: string; /** * statsd port. If not set, use the hot-shots default, 8125 * at the time of this writing. */ port?: number; }; /** Register a custom secret resolver */ secretResolver?: SecretResolver; /** Register a custom AutomationMetadataProcessor */ metadataProcessor?: AutomationMetadataProcessor; } /** * Atomist automation configuration. */ export interface Configuration extends AutomationServerOptions { /** * Automation commands this package provides. If empty or null, * the package will be scanned for commands, which must be under a * directory named "commands". */ commands?: Array>; /** * Automation event handlers this package provides. If empty or * null, the package will be scanned for event handlers, which * must be under a directory named "events". */ events?: Array>; /** Custom event ingester */ ingesters?: Array; /** Log and metric sinks */ listeners?: AutomationEventListener[]; } /** * User per-automation configuration */ export interface ModuleOptions extends AutomationServerOptions { /** Automation name this configuration applies to. */ name: string; /** * A valid version or version range, as defined by * https://www.npmjs.com/package/semver, this configurarion * applies to. If not provided, it applies to all versions of the * named automation. */ version?: string; } /** * User-wide configuration and user per-automation configuration */ export interface UserConfig extends AutomationServerOptions { modules?: ModuleOptions[]; } /** * Generate defaults for various configuration option values. These * will only be used if values are not provided by any source. Values * not provided here will be `undefined`. * * @return default configuration */ export declare function defaultConfiguration(): Configuration; /** * Exposes the configuration for lookup of configuration values. * This is useful for components to obtain values eg. from configuration.custom * like user provided secrets etc. * @param {string} path the property path evaluated against the configuration instance * @returns {T} */ export declare function configurationValue(path: string, defaultValue?: T): T; /** * Return user automation client configuration path. */ export declare function userConfigPath(): string; /** * Write user config securely, creating directories as necessary. */ export declare function writeUserConfig(cfg: UserConfig): Promise; /** * Read and return user config from UserConfigFile. */ export declare function getUserConfig(): UserConfig; /** * Overwrite values in the former configuration with values in the * latter. The start object is modified. * * @param obj starting configuration * @param override configuration values to add/override those in start * @return resulting merged configuration */ export declare function mergeConfigs(obj: Configuration, ...sources: Configuration[]): Configuration; /** * Merge a user's global and proper per-module configuration, if it * exists. Values from the per-module configuration take precedence * over the user-wide values. Per-module configuration is gotten from * the first per-module configuration that matches name and, * optionally, the version is within the per-module configuration's * version range. A module configuration without a version range * matches the named module with any version. If no version is * provided, any version range is satisfied, meaning the first * per-module configuration with a matching name is used. If no name * is provide, only the user configuration is loaded. The first * per-module match is used. This means if you have multiple * configurations for the same named module and you want to include a * default configuration for that module, put a configuration without * a version range _after_ all the configurations with version ranges. * Note that only values from the first per-module match are used. * * @param userConfig the user's configuration, which may include per-module configuration * @param name automation client package name to load as module config if it exists * @param version automation client package version to load as module config if * version satifies module config version range * @return the merged module and user configuration */ export declare function resolveModuleConfig(userConfig: UserConfig, name?: string, version?: string): AutomationServerOptions; /** * Try to read user config, overriding its values with a per-module * configuration that matches this automation. * * @param name automation client package name to load as module config if it exists * @param version automation client package version to load as module config if * version satifies module config version range * @return module-specific config with user config supplying defaults */ export declare function loadUserConfiguration(name?: string, version?: string): AutomationServerOptions; /** * Load the automation configuration from the configuration object * exported from cfgPath and return it. If no configuration path is * provided, the package will be searched for a file named * atomist.config.js. If no atomist.config.js is found, an empty * object is returned. If more than one is found, an exception is * thrown. * * @param cfgPath location of automation configuration * @return automation configuration */ export declare function loadAutomationConfig(cfgPath?: string): Configuration; /** * Load configuration from the file defined by the ATOMIST_CONFIG_PATH * environment variable, if it the variable is defined and the file * exists, and return it. The contents of the ATOMIST_CONFIG_PATH * file should be serialized JSON of AutomationServerOptions. If the * environment variable is not defined or the file path specified by * its value cannot be read as JSON, an empty object is returned. * * @return automation server options */ export declare function loadAtomistConfigPath(): AutomationServerOptions; /** * Load configuration from the ATOMIST_CONFIG environment variable, if * it the variable is defined, and merge it into the passed in * configuration. The value of the ATOMIST_CONFIG environment * variable should be serialized JSON of AutomationServerOptions. The * values from the environment variable will override values in the * passed in configuration. If the environment variable is not * defined, the passed in configuration is returned unchanged. * * @return automation server options */ export declare function loadAtomistConfig(): AutomationServerOptions; /** * Examine environment, config, and cfg for Atomist team IDs. The * ATOMIST_TEAMS environment variable takes precedence over the * ATOMIST_TEAM environment variable, which takes precedence over the * configuration "teamdIds", which takes precedence over cfg.teamIds, * which may be undefined, null, or an empty array. * * @deprecated resolveTeamIds is deprecated and will be removed in a * future release */ export declare function resolveTeamIds(cfg: Configuration): string[]; /** * Examine environment, config, and cfg for Atomist workspace IDs. * The ATOMIST_WORKSPACES environment variable takes precedence over * the configuration "workspaceIds", which takes precedence over * cfg.workspaceId, which may be undefined, null, or an empty array. * If the ATOMIST_WORKSPACES environment variable is not set, * workspaceIds is not set in config, and workspaceIds is falsey in * cfg and teamIds is resolvable from the configuration, workspaceIds * is set to teamIds. * * @param cfg current configuration, whose workspaceIds and teamIds * properties may be modified by this function * @return the resolved workspace IDs */ export declare function resolveWorkspaceIds(cfg: Configuration): string[]; /** * Resolve a value from a environment variables or configuration keys. * The environment variables are checked in order and take precedence * over the configuration key, which are also checked in order. If * no truthy values are found, undefined is returned. * * @param environmentVariables environment variables to check * @param configKeyPaths configuration keys, as JSON paths, to check * @param defaultValue value to use if no environment variables or config keys have values * @return first truthy value found, or defaultValue */ export declare function resolveConfigurationValue(environmentVariables: string[], configKeyPaths: string[], defaultValue?: string): string; /** * Resolve the token from the environment and configuration. The * ATOMIST_TOKEN environment variable takes precedence over the * GITHUB_TOKEN environment variable, which takes precedence over the * config value, which takes precedence over the passed in value. * * @deprecated resolveToken is deprecated and will be removed in a * future release */ export declare function resolveToken(cfg: Configuration): string; /** * Resolve the HTTP port from the environment and configuration. The * PORT environment variable takes precedence over the config value. */ export declare function resolvePort(cfg: Configuration): number; /** * Resolve ATOMIST_ environment variables and add them to config. * Variables of like ATOMIST_custom_foo_bar will be converted to * a json path of custom.foo.bar. * @param {Configuration} cfg */ export declare function resolveEnvironmentVariables(cfg: Configuration): void; /** * Resolve placeholders against the process.env. * Placeholders should be of form ${ENV_VAR}. Placeholders support default values * in case they aren't defined: ${ENV_VAR:default value} * @param {Configuration} config */ export declare function resolvePlaceholders(cfg: Configuration): void; /** * Invoke postProcessors on the provided configuration. */ export declare function invokePostProcessors(cfg: Configuration): Promise; /** * Make sure final configuration has the minimum configuration it * needs. It will throw an error if required properties are missing. * * @param cfg final configuration */ export declare function validateConfiguration(cfg: Configuration): void; /** * Load and populate the automation configuration. The configuration * is loaded from several locations with the following precedence from * highest to lowest. * * 0. Recognized environment variables (see below) * 1. The value of the ATOMIST_CONFIG environment variable, parsed as * JSON and cast to AutomationServerOptions * 2. The contents of the ATOMIST_CONFIG_PATH file as AutomationServerOptions * 3. The automation's atomist.config.js exported configuration as * Configuration * 4. The contents of the user's client.config.json as UserConfig * resolving user and per-module configuration into Configuration * 5. ProductionDefaultConfiguration if ATOMIST_ENV or NODE_ENV is set * to "production" or TestingDefaultConfiguration if ATOMIST_ENV or * NODE_ENV is set to "staging" or "testing", with ATOMIST_ENV * taking precedence over NODE_ENV. * 6. LocalDefaultConfiguration * * If any of the sources are missing, they are ignored. Any truthy * configuration values specified by sources of higher precedence * cause any values provided by sources of lower precedence to be * ignored. Arrays are replaced, not merged. Typically the only * required values in the configuration for a successful registration * are the apiKey or token and non-empty workspaceIds. * * Placeholder of the form `${ENV_VARIABLE}` in string configuration * values will get resolved against the environment. The resolution * happens at the very end when all configs have been merged. * * The configuration exported from the atomist.config.js is modified * to contain the final configuration values and returned from this * function. * * @param cfgPath path to file exporting the configuration object, if * not provided the package is searched for one * @return merged configuration object */ export declare function loadConfiguration(cfgPath?: string): Promise; /** * Default configuration when running in neither testing or * production. */ export declare const LocalDefaultConfiguration: Configuration; /** * Configuration defaults for production environments. */ export declare const ProductionDefaultConfiguration: Partial; /** * Configuration defaults for pre-production environments. */ export declare const TestingDefaultConfiguration: Partial; //# sourceMappingURL=configuration.d.ts.map