UNPKG

@atomist/sdm-pack-aspect

Version:

an Atomist SDM Extension Pack for visualizing drift across an organization

218 lines (176 loc) 5.72 kB
/* * Copyright © 2019 Atomist, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { RepoRef, Severity, } from "@atomist/automation-client"; import { FP } from "@atomist/sdm-pack-fingerprint"; import { Aspect } from "@atomist/sdm-pack-fingerprint/lib/machine/Aspect"; import { FingerprintUsage } from "../analysis/offline/persist/ProjectAnalysisResultStore"; import { ProjectAnalysisResult } from "../analysis/ProjectAnalysisResult"; import { Scorer, ScorerReturn, WeightedScore, } from "../scorer/Score"; import { IdealStore } from "./IdealStore"; import { ProblemStore, UndesirableUsageChecker, } from "./ProblemStore"; /** * Implemented by ProjectAnalysis or any other structure * representing a repo exposing fingerprint data */ export interface HasFingerprints { fingerprints: FP[]; } /** * Result of an analysis. We must always have at least fingerprints and repo identification */ export type Analyzed = HasFingerprints & { id: RepoRef }; /** * Tag based on fingerprint data. */ export interface Tag { name: string; /** * Name of parent tag */ parent?: string; description?: string; /** * Severity if this tag is associated with an action */ severity?: Severity; } export type TagTest = (repoToScore: RepoToScore) => Promise<boolean>; /** * Determine zero or one tag in this fingerprint. */ export interface Tagger extends Tag { /** * Test for the relevance of this tag. Invoked on every fingerprint * on each project. */ test: TagTest; } /** * Implemented by objects that can create tag tests. Tag information is * known in advance. Tests are dynamically created. */ export interface WorkspaceSpecificTagger extends Tag { createTest(workspaceId: string, ar: AspectRegistry): Promise<TagTest>; } /** * Tagger that can apply to all workspaces or workspace-specific tagger */ export type TaggerDefinition = Tagger | WorkspaceSpecificTagger; export function isTagger(t: TaggerDefinition): t is Tagger { const maybe = t as Tagger; return !!maybe.test; } export type TaggedRepo = RepoToScore & { tags?: Tag[] }; export type ScoredRepo = TaggedRepo & { weightedScore: WeightedScore }; export type RepoToScore = Pick<ProjectAnalysisResult, "analysis" | "id">; /** * Scoring repository based on * fingerprints that have previously been extracted by aspects. * @param repo repo we are scoring * @param allRepos context of this scoring activity * @return undefined if this scorer doesn't know how to score this repository. * Otherwise return a score. */ export interface RepositoryScorer extends Scorer { /** * Does this scorer apply only to the root of a repository, rather than multiple subprojects? * See Aspect.baseOnly */ readonly baseOnly?: boolean; /** * If this is turned off, show all fingerprints, not just limited to current path. * Means that baseOnly is irrelevant. Will run only once on all fingerprints in all cases. */ readonly scoreAll?: boolean; /** * Function that knows how to score a repository. * @param repo repo we are scoring * @param allRepos context of this scoring activity * @return undefined if this scorer doesn't know how to score this repository. */ scoreFingerprints: (r: RepoToScore) => Promise<ScorerReturn>; } export interface TagAndScoreOptions { /** * If this is set, score only for this category * '*' means all */ readonly category?: string; } /** * Information on which we'll score an organization */ export interface WorkspaceToScore { /** * Information about this organization */ fingerprintUsage: FingerprintUsage[]; /** * Repos that have already been scored */ repos: Array<{ url: string; repo: string; owner: string; score?: number; }>; } export interface WorkspaceScorer extends Scorer { /** * Function that knows how to score an org. * @param repo repo we are scoring * @param allRepos context of this scoring activity * @return undefined if this scorer doesn't know how to score this repository. */ score: (od: WorkspaceToScore) => Promise<ScorerReturn>; } /** * Manage a number of aspects. */ export interface AspectRegistry { scoreWorkspace(workspaceId: string, workspaceToScore: WorkspaceToScore): Promise<WeightedScore>; tagAndScoreRepos(workspaceId: string, repos: ProjectAnalysisResult[], opts: TagAndScoreOptions): Promise<ScoredRepo[]>; availableTags: Tag[]; /** * All the aspects we are managing */ readonly aspects: Aspect[]; /** * Find the aspect that manages fingerprints of this type */ aspectOf(type: string): Aspect | undefined; /** * Function that can resolve ideal status for this aspect */ readonly idealStore: IdealStore; readonly problemStore: ProblemStore; /** * Return an UndesirableUsageChecker for this workspace */ undesirableUsageCheckerFor(workspaceId: string): Promise<UndesirableUsageChecker | undefined>; }