@atomist/sdm
Version:
Atomist Software Delivery Machine SDK
174 lines (152 loc) • 5.29 kB
text/typescript
/*
* Copyright © 2020 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 { GitProject } from "@atomist/automation-client/lib/project/git/GitProject";
import { Goal, GoalDefinition } from "../../../api/goal/Goal";
import { DefaultGoalNameGenerator } from "../../../api/goal/GoalNameGenerator";
import {
FulfillableGoalDetails,
FulfillableGoalWithRegistrations,
getGoalDefinitionFrom,
ImplementationRegistration,
mergeOptions,
} from "../../../api/goal/GoalWithFulfillment";
import { IndependentOfEnvironment } from "../../../api/goal/support/environment";
import { DockerProgressReporter } from "./DockerProgressReporter";
import { DefaultDockerImageNameCreator, DockerImageNameCreator, executeDockerBuild } from "./executeDockerBuild";
export interface DockerRegistry {
/**
* Push Url for this registry
*/
registry: string;
/**
* Should this registry be displayed with the goal status after a push? Default true.
*/
display?: boolean;
/**
* Display Url - ie the url humans can go to
* assumes <url>/<image>
*/
displayUrl?: string;
/**
* If specified, this will replace the label version details (eg <image><:version>)
* For example, for Dockerhub the correct value would be `/tags`, with a displayUrl set
* to https://hub.docker.com/r/<user/org>; will result in:
* https://hub.docker.com/r/<user/org>/<image>/tags as the link URL
*
*/
displayBrowsePath?: string;
/**
* How should urls to this registry be labeled?
* ie DockerHub, ECR, etc (friendly name instead of big tag string)
* if not supplied, we'll display the tag
*/
label?: string;
user?: string;
password?: string;
}
/**
* Options to configure the Docker image build
*/
export interface DockerOptions extends Partial<ImplementationRegistration> {
/**
* Provide the image tag for the docker image to build
*/
dockerImageNameCreator?: DockerImageNameCreator;
/**
* True if the docker image should be pushed to the registry
*/
push?: boolean;
/**
* True if pushes should happen concurrently
*/
concurrentPush?: boolean;
/**
* Optional registries to push the docker image too.
* Needs to set when push === true
*/
registry?: DockerRegistry | DockerRegistry[];
/**
* Optional Docker config in json as alternative to running
* 'docker login' with provided registry, user and password.
*/
config?: string;
/**
* Find the Dockerfile within the project
* @param p the project
*/
dockerfileFinder?: (p: GitProject) => Promise<string>;
/**
* Optionally specify what docker image builder to use.
* Defaults to "docker"
*/
builder?: "docker" | "kaniko";
/**
* Optional arguments passed to the docker image builder
*/
builderArgs?: string[];
/**
* Path relative to base of project to build. If not provided,
* ".", i.e., the project base directory, is used.
*/
builderPath?: string;
}
const DefaultDockerOptions: DockerOptions = {
dockerImageNameCreator: DefaultDockerImageNameCreator,
dockerfileFinder: async () => "Dockerfile",
builder: "docker",
builderArgs: [],
builderPath: ".",
};
/**
* Goal that performs docker build and push depending on the provided options
*/
export class DockerBuild extends FulfillableGoalWithRegistrations<DockerOptions> {
constructor(
goalDetailsOrUniqueName: FulfillableGoalDetails | string = DefaultGoalNameGenerator.generateName(
"docker-build",
),
...dependsOn: Goal[]
) {
super(
getGoalDefinitionFrom(
goalDetailsOrUniqueName,
DefaultGoalNameGenerator.generateName("docker-build"),
DockerBuildDefinition,
),
...dependsOn,
);
}
public with(registration: DockerOptions): this {
const optsToUse = mergeOptions<DockerOptions>(DefaultDockerOptions, registration);
this.addFulfillment({
goalExecutor: executeDockerBuild(optsToUse),
name: DefaultGoalNameGenerator.generateName("docker-builder"),
progressReporter: DockerProgressReporter,
...(registration as ImplementationRegistration),
});
return this;
}
}
const DockerBuildDefinition: GoalDefinition = {
uniqueName: "docker-build",
displayName: "docker build",
environment: IndependentOfEnvironment,
workingDescription: "Running docker build",
completedDescription: "Docker build successful",
failedDescription: "Docker build failed",
isolated: true,
retryFeasible: true,
};