@atomist/sdm-pack-aspect
Version:
an Atomist SDM Extension Pack for visualizing drift across an organization
193 lines (159 loc) • 6.35 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 } from "@atomist/automation-client";
import { FP } from "@atomist/sdm-pack-fingerprint";
import { Analyzed } from "../../../aspect/AspectRegistry";
import {
PlantedTree,
TagUsage,
} from "../../../tree/sunburst";
import { ProjectAnalysisResult } from "../../ProjectAnalysisResult";
import { CohortAnalysis } from "../spider/analytics";
import {
PersistenceResult,
SpiderFailure,
} from "../spider/Spider";
export interface PersistResult {
attemptedCount: number;
failed: SpiderFailure[];
succeeded: PersistenceResult[];
failedFingerprints: Array<{ failedFingerprint: FP; error: Error }>;
}
export function combinePersistResults(r1: PersistResult, r2: PersistResult): PersistResult {
return {
attemptedCount: r1.attemptedCount + r2.attemptedCount,
failed: [...r1.failed, ...r2.failed],
succeeded: [...r1.succeeded, ...r2.succeeded],
failedFingerprints: [...r1.failedFingerprints, ...r2.failedFingerprints],
};
}
export const emptyPersistResult: PersistResult = {
attemptedCount: 0,
failed: [],
succeeded: [],
failedFingerprints: [],
};
export type FingerprintKind = Pick<FP, "type" | "name">;
/**
* Data about the use of a fingerprint in a workspace
*/
export interface FingerprintUsage extends CohortAnalysis {
name: string;
type: string;
}
export interface TreeQuery {
workspaceId: string;
aspectName: string;
rootName: string;
/**
* Look for one particular fingerprint?
*/
byName: boolean;
/**
* If this is supplied, query for results even without fingerprints from this aspect
* and use this as the name
*/
otherLabel?: string;
}
export interface FingerprintInsertionResult {
insertedCount: number;
failures: Array<{ failedFingerprint: FP; error: Error }>;
}
/**
* Interface for basic persistence operations.
* Implementations can provide additional querying options,
* e.g. through SQL.
* '*' is consistently used in place for workspaceId to return
* data for all workspaces.
*/
export interface ProjectAnalysisResultStore {
fingerprintsToReposTree(tq: TreeQuery): Promise<PlantedTree>;
/**
* Drift tree
* @param {string} workspaceId
* @param {number} percentile (0-100). Show fingerprints only with entropy above this
* @param {options} include repositories as leaves; type if provided, show drift only
* for the particular aspect. Otherwise show drift for all aspects.
* @return {Promise<PlantedTree>}
*/
aspectDriftTree(workspaceId: string,
percentile: number,
options?: { repos?: boolean, type?: string }): Promise<PlantedTree>;
/**
* How many repos we've analyzed
*/
distinctRepoCount(workspaceId: string): Promise<number>;
/**
* Virtual project count. One repository may contain multiple virtual projects
*/
virtualProjectCount(workspaceId: string): Promise<number>;
/**
* What's the most recent snapshot timestamp we've seen in this workspace?
* @param {string} workspaceId
* @return {Promise<Date>}
*/
latestTimestamp(workspaceId: string): Promise<Date>;
/**
* Load in the given workspace
* @param workspaceId '*' for all workspaces
* @param deep whether to load deep
*/
loadInWorkspace(workspaceId: string, deep: boolean): Promise<ProjectAnalysisResult[]>;
loadByRepoRef(repo: RepoRef, deep: boolean): Promise<ProjectAnalysisResult | undefined>;
/**
* Load by our database id
* @param {string} id
* @return {Promise<ProjectAnalysisResult | undefined>}
*/
loadById(id: string, deep: boolean): Promise<ProjectAnalysisResult | undefined>;
persist(repos: ProjectAnalysisResult | AsyncIterable<ProjectAnalysisResult> | ProjectAnalysisResult[]): Promise<PersistResult>;
/**
* Persist fingerprints for this snapshot id, which must already exist.
*/
persistAdditionalFingerprints(analyzed: Analyzed): Promise<FingerprintInsertionResult>;
/**
* Return distinct fingerprint type/name combinations in this workspace
*/
distinctFingerprintKinds(workspaceId: string): Promise<FingerprintKind[]>;
/**
* Return distinct fingerprint type/name combinations in this workspace by repo
*/
distinctRepoFingerprintKinds(workspaceId: string): Promise<Array<{ owner: string, repo: string, fingerprints: FingerprintKind[] }>>;
fingerprintUsageForType(workspaceId: string, type?: string): Promise<FingerprintUsage[]>;
tags(workspaceId: string): Promise<TagUsage[]>;
/**
* Persist a record of analytics. Can be invoked repeatedly on the same data without error.
*/
persistAnalytics(params: Array<{ workspaceId: string, kind: FingerprintKind, cohortAnalysis: CohortAnalysis }>): Promise<boolean>;
/**
* Return all the fingerprints in this workspace, optionally narrowed by type and name
* @param workspaceId workspaceId. Use * for all workspaces
* @param distinct whether to remove duplicates
* @param type fingerprint type (optional)
* @param name fingerprint name (optional)
*/
fingerprintsInWorkspace(workspaceId: string,
distinct: boolean,
type?: string,
name?: string): Promise<Array<FP & { id: string }>>;
fingerprintsForProject(id: string): Promise<Array<FP & { timestamp: Date, commitSha: string }>>;
/**
* Return the average number of fingerprints in the workspace
* @param {string} workspaceId
* @return {Promise<number>}
*/
averageFingerprintCount(workspaceId?: string): Promise<number>;
}