"use strict";
/*
 * 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.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.initiateKubernetesDeploy = exports.defaultDataSources = exports.KubernetesDeploy = exports.KubernetesDeployDataSources = exports.goalEventSlug = void 0;
const _ = require("lodash");
const GoalNameGenerator_1 = require("../../../api/goal/GoalNameGenerator");
const GoalWithFulfillment_1 = require("../../../api/goal/GoalWithFulfillment");
const commonPushTests_1 = require("../../../api/mapping/support/commonPushTests");
const modes_1 = require("../../../core/machine/modes");
const types_1 = require("../../../typings/types");
const cluster_1 = require("./cluster");
const data_1 = require("./data");
const deploy_1 = require("./deploy");
/** Return repository slug for SDM goal event. */
function goalEventSlug(goalEvent) {
    return `${goalEvent.repo.owner}/${goalEvent.repo.name}`;
}
exports.goalEventSlug = goalEventSlug;
/**
 * Sources of information for Kubernetes goal application data.
 */
var KubernetesDeployDataSources;
(function (KubernetesDeployDataSources) {
    /** Read deployment spec from `.atomist/kubernetes`. */
    KubernetesDeployDataSources["DeploymentSpec"] = "DeploymentSpec";
    /** Read EXPOSE from Dockerfile to get service port. */
    KubernetesDeployDataSources["Dockerfile"] = "Dockerfile";
    /** Parse `goalEvent.data` as JSON. */
    KubernetesDeployDataSources["GoalEvent"] = "GoalEvent";
    /** Read ingress spec from `.atomist/kubernetes`. */
    KubernetesDeployDataSources["IngressSpec"] = "IngressSpec";
    /** Read role-binding spec from `.atomist/kubernetes`. */
    KubernetesDeployDataSources["RoleBindingSpec"] = "RoleBindingSpec";
    /** Read role spec from `.atomist/kubernetes`. */
    KubernetesDeployDataSources["RoleSpec"] = "RoleSpec";
    /** Load `sdm.configuration.sdm.k8s.app`. */
    KubernetesDeployDataSources["SdmConfiguration"] = "SdmConfiguration";
    /** Read service-account spec from `.atomist/kubernetes`. */
    KubernetesDeployDataSources["ServiceAccountSpec"] = "ServiceAccountSpec";
    /** Read service spec from `.atomist/kubernetes`. */
    KubernetesDeployDataSources["ServiceSpec"] = "ServiceSpec";
})(KubernetesDeployDataSources = exports.KubernetesDeployDataSources || (exports.KubernetesDeployDataSources = {}));
/**
 * Goal that initiates deploying an application to a Kubernetes
 * cluster.  Deploying the application is completed by the
 * [[kubernetesDeployHandler]] event handler.  By default, this goal
 * will be configured such that it is fulfilled by the SDM that
 * creates it.  To have this goal be executed by another SDM, set the
 * fulfillment name to the name of that SDM:
 *
 *     const deploy = new KubernetesDeploy()
 *         .with({ name: otherSdm.configuration.name });
 *
 */
class KubernetesDeploy extends GoalWithFulfillment_1.FulfillableGoalWithRegistrations {
    /**
     * Create a KubernetesDeploy object.
     *
     * @param details Define unique aspects of this Kubernetes deployment, see [[KubernetesDeploy.details]].
     * @param dependsOn Other goals that must complete successfully before scheduling this goal.
     */
    constructor(details = {}, ...dependsOn) {
        super(GoalWithFulfillment_1.getGoalDefinitionFrom(details, GoalNameGenerator_1.DefaultGoalNameGenerator.generateName("kubernetes-deploy")), ...dependsOn);
        this.details = details;
    }
    /**
     * Register a deployment with the initiator fulfillment.
     */
    with(registration) {
        const fulfillment = registration.name || this.sdm.configuration.name;
        this.addFulfillment({
            name: fulfillment,
            goalExecutor: initiateKubernetesDeploy(this, registration),
            pushTest: registration.pushTest,
        });
        this.updateGoalName(fulfillment);
        return this;
    }
    /**
     * Called by the SDM on initialization.  This function calls
     * `super.register` and adds a startup listener to the SDM.
     *
     * The startup listener registers a default goal fulfillment that
     * adds itself as fulfiller of its deployment requests if this
     * goal has no fulfillments or callbacks at startup.
     */
    register(sdm) {
        super.register(sdm);
        sdm.addStartupListener(async () => {
            if (this.fulfillments.length === 0 && this.callbacks.length === 0) {
                this.with({ pushTest: commonPushTests_1.AnyPush });
            }
        });
    }
    /**
     * Set the goal "name" and goal definition "displayName".  If any
     * goal definition description is not set, populate it with a
     * reasonable default.
     *
     * @param fulfillment Name of fulfillment, typically the cluster-scoped name of k8s-sdm
     * @return object
     */
    updateGoalName(fulfillment) {
        const env = (this.details && this.details.environment) ? this.details.environment : this.environment;
        const clusterLabel = cluster_1.getClusterLabel(env, fulfillment);
        const displayName = this.definition.displayName || "deploy";
        const goalName = `${displayName}${clusterLabel}`;
        this.definition.displayName = goalName;
        const defaultDefinitions = {
            canceledDescription: `Canceled: ${goalName}`,
            completedDescription: `Deployed${clusterLabel}`,
            failedDescription: `Deployment${clusterLabel} failed`,
            plannedDescription: `Planned: ${goalName}`,
            requestedDescription: `Requested: ${goalName}`,
            skippedDescription: `Skipped: ${goalName}`,
            stoppedDescription: `Stopped: ${goalName}`,
            waitingForApprovalDescription: `Successfully deployed${clusterLabel}`,
            waitingForPreApprovalDescription: `Deploy${clusterLabel} pending approval`,
            workingDescription: `Deploying${clusterLabel}`,
        };
        _.defaultsDeep(this.definition, defaultDefinitions);
        return this;
    }
}
exports.KubernetesDeploy = KubernetesDeploy;
/**
 * Populate data sources properrty of registration with all possible
 * KubernetesGoalDataSources if it is not defined.  Otherwise, leave
 * it as is.  The registration object is modified directly and
 * returned.
 *
 * @param registration Kubernetes deploy object registration
 * @return registration with data sources
 */
function defaultDataSources(registration) {
    if (!registration.dataSources) {
        registration.dataSources = Object.values(KubernetesDeployDataSources);
    }
    return registration;
}
exports.defaultDataSources = defaultDataSources;
/**
 * If in SDM team mode, this goal executor generates and stores the
 * Kubernetes application data for deploying an application to
 * Kubernetes.  It returns the augmented SdmGoalEvent with the
 * Kubernetes application information in the `data` property and the
 * state of the SdmGoalEvent set to "requested".  The actual
 * deployment is done by the [[kubernetesDeployHandler]] event
 * handler.
 *
 * It will call [[defaultDataSources]] to populate the default
 * repository data sources if none are provided in the registration.
 *
 * If in SDM local mode, generate the Kubernetes application data and
 * deploy the application.
 *
 * @param k8Deploy Kubernetes deploy object
 * @param registration Kubernetes deploy object registration
 * @return An ExecuteGoal result that is not really a result, but an intermediate state.
 */
function initiateKubernetesDeploy(k8Deploy, registration) {
    return async (goalInvocation) => {
        defaultDataSources(registration);
        const goalEvent = await data_1.generateKubernetesGoalEventData(k8Deploy, registration, goalInvocation);
        if (modes_1.isInLocalMode()) {
            return deploy_1.deployApplication(goalEvent, goalInvocation.context, goalInvocation.progressLog);
        }
        else {
            goalEvent.state = types_1.SdmGoalState.requested;
            return goalEvent;
        }
    };
}
exports.initiateKubernetesDeploy = initiateKubernetesDeploy;
//# sourceMappingURL=goal.js.map