@atomist/sdm-pack-aspect
Version:
an Atomist SDM Extension Pack for visualizing drift across an organization
218 lines (176 loc) • 5.72 kB
text/typescript
/*
* 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>;
}