@atomist/sdm-pack-aspect
Version:
an Atomist SDM Extension Pack for visualizing drift across an organization
188 lines (172 loc) • 7.89 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 {
GitHubRepoRef,
logger,
MappedParameters,
QueryNoCacheOptions,
} from "@atomist/automation-client";
import {
CommandHandlerRegistration,
DeclarationType,
execPromise,
isLazyProjectLoader,
ProviderType,
PushImpactListenerInvocation,
SoftwareDeliveryMachine,
} from "@atomist/sdm";
import {
Aspect,
fingerprintRunner,
} from "@atomist/sdm-pack-fingerprint";
import { sendFingerprintsToAtomist } from "@atomist/sdm-pack-fingerprint/lib/adhoc/fingerprints";
import { createFingerprintComputer } from "@atomist/sdm-pack-fingerprint/lib/machine/runner";
import * as _ from "lodash";
import {
GitHubAppInstallationByOwner,
IngestScmCommit,
ScmCommitInput,
ScmProviderById,
} from "../typings/types";
// tslint:disable-next-line:interface-over-type-literal
export type CalculateFingerprintTaskParameters = {
providerId: string,
repoId: string,
owner: string,
name: string,
branch: string,
};
export function calculateFingerprintTask(sdm: SoftwareDeliveryMachine,
aspects: Aspect[])
: CommandHandlerRegistration<CalculateFingerprintTaskParameters> {
// Also register the provided aspects in the registration metadata
sdm.configuration.metadata = {
...sdm.configuration.metadata,
"atomist.aspects": JSON.stringify(aspects.map(a => ({ name: a.name, displayName: a.displayName }))),
};
return {
name: "CalculateFingerprintTask",
description: "Trigger calculation of fingerprints on the provided repository",
parameters: {
providerId: { description: "Id of the SCMProvider" },
repoId: { description: "Id of the Repo" },
owner: { uri: MappedParameters.GitHubOwner, declarationType: DeclarationType.Mapped },
name: { uri: MappedParameters.GitHubRepository, declarationType: DeclarationType.Mapped },
branch: { description: "Name of the branch" },
},
listener: async ci => {
try {
const provider = _.get(await ci.context.graphClient.query<ScmProviderById.Query, ScmProviderById.Variables>({
name: "ScmProviderById",
variables: {
providerId: ci.parameters.providerId,
},
options: QueryNoCacheOptions,
}), "SCMProvider[0]");
const app = _.get(await ci.context.graphClient.query<GitHubAppInstallationByOwner.Query, GitHubAppInstallationByOwner.Variables>({
name: "GitHubAppInstallationByOwner",
variables: {
name: ci.parameters.owner,
},
options: QueryNoCacheOptions,
}), "GitHubAppInstallation[0]");
const token = _.get(provider, "credential.secret") || _.get(app, "token.secret");
const id = GitHubRepoRef.from({
owner: ci.parameters.owner,
repo: ci.parameters.name,
branch: ci.parameters.branch,
rawApiBase: provider.apiUrl,
});
const credentials = !!token ? { token } : undefined;
await ci.configuration.sdm.projectLoader.doWithProject({ ...ci, id, credentials }, async p => {
if (isLazyProjectLoader(ci.configuration.sdm.projectLoader)) {
await p.materialize();
}
// git rev-parse HEAD = sha
const sha = (await execPromise("git", ["rev-parse", "HEAD"], { cwd: p.baseDir })).stdout.trim();
// const author = (await execPromise("git", ["show", "-s", "--format=%an"], { cwd: p.baseDir })).stdout.trim();
const email = (await execPromise("git", ["show", "-s", "--format=%ae"], { cwd: p.baseDir })).stdout.trim();
const ts = (await execPromise("git", ["show", "-s", "--format=%at"], { cwd: p.baseDir })).stdout.trim();
const message = (await execPromise("git", ["show", "-s", "--format=%B"], { cwd: p.baseDir })).stdout.trim();
// Ingest initial commit
const commit: ScmCommitInput = {
repoId: ci.parameters.repoId,
branchName: ci.parameters.branch,
timestamp: new Date(+ts * 1000).toISOString(),
email: {
address: email,
},
sha,
message,
};
await ci.context.graphClient.mutate<IngestScmCommit.Mutation, IngestScmCommit.Variables>({
name: "IngestScmCommit",
variables: {
providerId: provider.id,
commit,
},
});
// Run the fingerprint code
const pi: PushImpactListenerInvocation = {
context: ci.context,
configuration: ci.configuration,
project: p,
addressChannels: ci.addressChannels,
preferences: ci.preferences,
credentials: ci.credentials,
id,
impactedSubProject: p,
filesChanged: undefined,
commit: {
sha,
message,
},
push: {
repo: {
defaultBranch: ci.parameters.branch,
channels: [],
name: ci.parameters.name,
owner: ci.parameters.owner,
org: {
owner: ci.parameters.owner,
provider: {
apiUrl: provider.apiUrl,
providerId: ci.parameters.providerId,
providerType: ProviderType.github_com,
},
},
},
after: {
sha,
message,
},
commits: [{
sha,
message,
}],
branch: ci.parameters.branch,
timestamp: ts,
},
};
const fingerprintComputer = createFingerprintComputer(aspects);
await fingerprintRunner(aspects, [], fingerprintComputer, sendFingerprintsToAtomist)(pi);
});
} catch (e) {
logger.error(`Fingerprinting task failed to execute: ${e.message}`);
}
},
};
}