@atomist/sdm-pack-aspect
Version:
an Atomist SDM Extension Pack for visualizing drift across an organization
124 lines (116 loc) • 4.8 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 {
CodeStats,
consolidate,
Language,
} from "@atomist/sdm-pack-sloc/lib/slocReport";
import * as _ from "lodash";
import { Analyzed } from "../aspect/AspectRegistry";
import { findCodeMetricsData } from "../aspect/common/codeMetrics";
import { Reporters } from "../aspect/reporters";
import { treeBuilder } from "../tree/TreeBuilder";
import { bandFor } from "../util/bands";
export type AnalyzedGrouper = (ar: Analyzed) => string;
const groupByLoc: AnalyzedGrouper = ar => {
const cm = findCodeMetricsData(ar);
if (!cm) {
return undefined;
}
return bandFor({
small: { upTo: 2000 },
tall: { upTo: 8000 },
grande: { upTo: 20000 },
venti: "default",
}, cm.lines);
};
/**
* Custom reporters against available repositories.
* Add your own here
*/
export const CustomReporters: Reporters = {
langs: {
summary: "Language breakdown across all projects",
description: "See the number of lines of code in each language, across all repos",
builder:
treeBuilder<Analyzed>("languages")
.customGroup<CodeStats>({
name: "language", to: async ars => {
const cms: CodeStats[] = [];
for await (const ar of ars) {
const cm = findCodeMetricsData(ar);
if (cm) {
cms.push(...cm.languages);
}
}
const distinctLanguages: Language[] = _.uniqBy(_.flatten(cms.map(cm => cm.language)), l => l.name);
const s: Record<string, CodeStats[]> = {};
distinctLanguages.forEach(lang => s[lang.name] = [consolidate(lang, cms)]);
return s;
},
})
.map<Analyzed & { lang: string }>({
async* mapping(cs: AsyncIterable<CodeStats>,
originalQuery: () => AsyncIterable<Analyzed>): AsyncIterable<Analyzed & { lang: string }> {
// TODO don't materialize this
const source: Analyzed[] = [];
for await (const pa of originalQuery()) {
source.push(pa);
}
for await (const s of cs) {
for (const r of source.filter(ar => {
const cm = findCodeMetricsData(ar) || { languages: [] };
return cm.languages.some(l => l.language.name === s.language.name);
})
.map(ar => ({ ...ar, lang: s.language.name }))) {
yield r;
}
}
},
})
.renderWith(ar => {
const cm = findCodeMetricsData(ar) || { languages: [] };
const size = cm.languages.find(l => l.language.name === ar.lang).total;
return {
name: ar.id.repo,
size,
url: `/projects/${ar.id.owner}/${ar.id.repo}`,
owner: ar.id.owner,
repoUrl: ar.id.url,
};
}),
},
loc: {
summary: "Drill into repositories",
description: "Compare the size and language breakdowns of your repos",
builder: treeBuilder<Analyzed>("loc")
.group({ name: "size", by: groupByLoc })
.split<CodeStats>({
splitter: ar => {
const cm = findCodeMetricsData(ar) || { languages: [] };
return cm.languages;
},
namer: a => a.id.repo,
})
.renderWith(cs => {
return {
name: `${cs.language.name} (${cs.source})`,
// url: ar.analysis.id.url,
size: cs.source,
};
}),
},
};