UNPKG

@atomist/sdm-pack-fingerprints

Version:

an Atomist SDM Extension Pack for fingerprinting code

229 lines (228 loc) 7.78 kB
import { HandlerContext, Project, ReviewComment } from "@atomist/automation-client"; import { SdmContext } from "@atomist/sdm"; import { GitCoordinate } from "../support/messages"; import { GetFpTargets } from "../typings/types"; import { Ideal } from "./Ideal"; /** * Fingerprint interface. An Aspect can emit zero or more fingerprints, * which must have the same data type. * @param DATA type parameter for data */ export interface FP<DATA = any> { type?: string; name: string; sha: string; data: DATA; version?: string; abbreviation?: string; /** * Path within the repository. Undefined means root. */ path?: string; } export interface Vote { abstain: boolean; decision?: string; name?: string; fingerprint?: FP; fpTarget?: FP; diff?: Diff; text?: string; summary?: { title: string; description: string; }; } /** * Difference between two fingerprints */ export interface Diff { from: FP; to: FP; data: { from: any[]; to: any[]; }; owner: string; repo: string; sha: string; providerId: string; channel: string; branch: string; } /** * Extract fingerprint(s) from the given project. * Return undefined or the empty array if no fingerprints found. */ export declare type ExtractFingerprint<FPI extends FP = FP> = (p: Project) => Promise<FPI | FPI[]>; export declare type FingerprintSelector = (fingerprint: FP) => boolean; /** * Apply the given fingerprint to the project */ export declare type ApplyFingerprint<FPI extends FP = FP> = (p: Project, fp: FPI) => Promise<boolean>; export interface DiffSummary { title: string; description: string; } export declare type DiffSummaryFingerprint = (diff: Diff, target: FP) => DiffSummary; /** * Implemented by types that know how to compare two fingerprints, * for example by quality or up-to-dateness */ export interface FingerprintComparator<FPI extends FP = FP> { readonly name: string; comparator: (a: FPI, b: FPI) => number; } /** * Common properties for all aspects. * Aspects add the ability to manage a particular type of fingerprint: * for example, helping with convergence across an organization and supporting * visualization. Aspects are typically extracted from a Project (see Aspect) * but may also be built from existing fingerprints (AtomicAspect) or derived from * an intermediate representation such as a ProjectAnalysis (DerivedAspect). * The structure (that is, the data payload) of all fingerprints emitted by an aspect * should be the same. */ export interface BaseAspect<FPI extends FP = FP> { /** * Displayable name of this aspect. Used only for reporting. * Set to undefined to prevent this aspect influencing * display to users. */ readonly displayName: string; /** * prefix for all fingerprints that are emitted by this Aspect */ readonly name: string; /** * Link to documentation for this Aspect. This can help people * understand the results graphs and results from the analysis * enabled here. * * You might provide a link to the typedoc for Aspects you define, * or an internal page describing why you created this and what * people can do about their results. */ readonly documentationUrl?: string; /** * Function to apply the given fingerprint instance to a project */ apply?: ApplyFingerprint<FPI>; summary?: DiffSummaryFingerprint; /** * Functions that can be used to compare fingerprint instances managed by this * aspect. */ comparators?: Array<FingerprintComparator<FPI>>; /** * Convert a fingerprint value to a human readable string * fpi.data is a reasonable default */ toDisplayableFingerprint?(fpi: FPI): string; /** * Convert a fingerprint name such as "npm-project-dep::atomist::automation-client" * to a human readable form such as "npm package @atomist/automation-client" * @param {string} fingerprintName * @return {string} */ toDisplayableFingerprintName?(fingerprintName: string): string; /** * Validate the aspect. Return undefined or the empty array if there are no problems. * @return {Promise<ReviewComment[]>} */ validate?(fpi: FPI): Promise<ReviewComment[]>; /** * Based on the given fingerprint type and name, suggest ideals * order of recommendation strength */ suggestedIdeals?(type: string, fingerprintName: string): Promise<Ideal[]>; /** * Workflows to be invoked on a fingerprint change. This supports use cases such as * reacting to a potential impactful change and cascading changes to other projects. */ workflows?: FingerprintDiffHandler[]; /** * Indications about how to calculate stats for this aspect across * multiple projects. An aspect without AspectStats will have its entropy * calculated by default. */ stats?: AspectStats; /** * Does this aspect apply only to the root of a repository, rather than multiple subprojects? */ readonly baseOnly?: boolean; } /** * Type for default stats that can be calculated on any feature. */ export declare type DefaultStat = "entropy"; /** * Type to use to customize calculation of default stats, such as entropy. * By default, all default stats are calculated and exposed. * To disable any, set a value of false for the key (such as "entropy"). A value of true * continues to include the stat. */ export declare type DefaultStatStatus = Partial<Record<DefaultStat, boolean>>; /** * Indication about how to calculate custom stats across multiple projects for an Aspect. */ export interface AspectStats { /** * Set the status for calculating and exposing default stats, such as entropy. * Some may be irrelevant for this aspect. * Default is to calculate all stats. */ defaultStatStatus?: DefaultStatStatus; /** * Path inside JSON data structure to compute mean, stdev etc. * The value at this path must be numeric. If an aspect appears to need multiple * basicStatsPaths, break it up into finer grained aspects. */ basicStatsPath?: string; } /** * Does this aspect support entropy, or is it turned off? */ export declare function supportsEntropy(ba: BaseAspect): boolean; /** * Aspect that extracts fingerprints directly from a Project. */ export interface Aspect<FPI extends FP = FP> extends BaseAspect<FPI> { /** * Function to extract fingerprint(s) from this project */ extract: ExtractFingerprint<FPI>; } export interface DiffContext extends Diff { targets: GetFpTargets.Query; } export declare type FingerprintDiffHandler = (context: SdmContext, diff: DiffContext, aspect: Aspect) => Promise<Vote>; /** * Handles differences between fingerprints across pushes and between targets. * Different strategies can be used to handle PushImpactEventHandlers. * */ export interface FingerprintHandler { /** * Is this handler able to manage this fingerprint instance? */ selector: (name: FP) => boolean; /** * Called when shas differ across pushes * @param {HandlerContext} context * @param {Diff} diff * @return {Promise<Vote>} */ diffHandler?: FingerprintDiffHandler; /** * Called when target fingerprint differs from current fingerprint * @param {HandlerContext} context * @param {Diff} diff * @return {Promise<Vote>} */ handler?: FingerprintDiffHandler; /** * For collecting results on all fingerprint diff handlers */ ballot?: (context: HandlerContext, votes: Vote[], coord: GitCoordinate, channel: string) => Promise<any>; }