@webda/shell
Version:
Deploy a Webda app or configure it
316 lines • 9.81 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Cache, FileUtils, JSONUtils, UnpackedApplication, WebdaError } from "@webda/core";
import { execSync } from "child_process";
import dateFormat from "dateformat";
import * as fs from "fs";
import * as merge from "merge";
import * as path from "path";
import semver from "semver";
import { Compiler } from "./compiler.js";
export class SourceApplication extends UnpackedApplication {
constructor() {
super(...arguments);
/**
* Flag if application has been compiled already
*/
this.compiled = false;
}
getCompiler() {
this.compiler ?? (this.compiler = new Compiler(this));
return this.compiler;
}
/**
* Get the Webda namespace
*/
getNamespace() {
return this.getPackageWebda().namespace || "webda";
}
/**
* Retrieve Git Repository information
*
* {@link GitInformation} for more details on how the information is gathered
* @return the git information
*/
getGitInformation(packageName = "", version = "") {
let options = {
cwd: this.getAppPath()
};
try {
// If git information are defined in env - useful for container build
if (process.env.GIT_INFO) {
return JSON.parse(Buffer.from(process.env.GIT_INFO, "base64").toString());
}
let tags = execSync(`git tag --points-at HEAD`, options)
.toString()
.trim()
.split("\n")
.filter(t => t !== "");
let tag = "";
if (tags.includes(`${packageName}@${version}`)) {
tag = `${packageName}@${version}`;
}
else if (tags.includes(`v${version}`)) {
tag = `v${version}`;
}
else {
version = semver.inc(version, "patch") + "+" + dateFormat(new Date(), "yyyymmddHHMMssl");
}
// Search for what would be the tag
// packageName@version
// or version if single repo
// if not included create a nextVersion+SNAPSHOT.${commit}.${now}
return {
commit: execSync(`git rev-parse HEAD`, options).toString().trim(),
branch: execSync("git symbolic-ref --short HEAD", options).toString().trim(),
short: execSync(`git rev-parse --short HEAD`, options).toString().trim(),
tag,
tags,
version
};
}
catch (err) {
return {
commit: "unknown",
branch: "unknown",
tag: "",
short: "00000000",
tags: [],
version
};
}
}
/**
* Set the status of the compilation
*
* @param compile true will avoid trigger new compilation
*/
preventCompilation(compile) {
this.compiled = compile;
}
/**
* Generate the module for current application
*/
async generateModule() {
// Compile
if (!this.compile()) {
return false;
}
// Write module
FileUtils.save(this.getCompiler().generateModule(), this.getAppPath("webda.module.json"));
return true;
}
/**
* Get the application files
*/
getPackagesLocations() {
return this.baseConfiguration.cachedModules?.project?.package?.files || ["lib/**/*.js"];
}
/**
* Compile the application if it is a Typescript application
* Do nothing otherwise
*/
compile() {
if (!this.compiled) {
this.compiled = this.getCompiler().compile();
}
return this.compiled;
}
/**
* Return the application Configuration for a deployment
*
* Given this inputs:
*
* webda.config.json
* ```json
* {
* "parameters": {
* "param3": "test"
* },
* "services": {
* "MyService": {
* "param1": {
* "sub": "test"
* },
* "param2": "value"
* }
* }
* }
* ```
*
* deployment.json
* ```json
* {
* "parameters": {
* "param4": "deployment"
* }
* "services": {
* "MyService": {
* "param1": {
* "sub2": "deploymentSub"
* },
* "param2": "${package.version}"
* }
* }
* }
* ```
*
* The result would be:
* ```json
* {
* "parameters": {
* "param3": "test",
* "param4": "deployment"
* },
* "services": {
* "MyService": {
* "param1": {
* "sub": "test",
* "sub2": "deploymentSub"
* },
* "param2": "1.1.0"
* }
* }
* }
* ```
* This map can also use parameters {@link replaceVariables}
*
* @param deploymentName to use for the Configuration
*/
getConfiguration(deploymentName = undefined) {
if (!deploymentName) {
return this.baseConfiguration;
}
let config = JSONUtils.duplicate(this.baseConfiguration);
let deploymentModel = this.getDeployment(deploymentName);
config.parameters = this.replaceVariables(merge.recursive(config.parameters, deploymentModel.parameters));
config.services = this.replaceVariables(merge.recursive(config.services, deploymentModel.services));
return config;
}
/**
* Return current Configuration of the Application
*
* Same as calling
*
* ```js
* getConfiguration(this.currentDeployment);
* ```
*/
getCurrentConfiguration() {
return this.getConfiguration(this.currentDeployment);
}
/**
* Get current deployment name
*/
getCurrentDeployment() {
return this.currentDeployment;
}
/**
* Set the current deployment for the application
* Call to getCurrentConfiguration will resolve to the computed configuration for the deployment
* If needed, you can call the method with undefined to reset to default configuration
*
* @param deployment to set
*/
setCurrentDeployment(deployment) {
this.currentDeployment = deployment;
}
/**
* Load a deployment configuration
*
* @param deploymentName
* @returns
*/
getDeployment(deploymentName = undefined) {
if (!deploymentName) {
deploymentName = this.currentDeployment;
}
this.deploymentFile = undefined;
let deploymentConfig;
for (let ext of [".jsonc", ".json", ".yaml", ".yml"]) {
deploymentConfig = path.join(this.appPath, "deployments", `${deploymentName}${ext}`);
if (fs.existsSync(deploymentConfig)) {
break;
}
}
if (!fs.existsSync(deploymentConfig)) {
throw new WebdaError.CodeError("UNKNOWN_DEPLOYMENT", "Unknown deployment");
}
let deploymentModel;
try {
deploymentModel = FileUtils.load(deploymentConfig);
deploymentModel.name = deploymentName;
}
catch (err) {
throw new WebdaError.CodeError("INVALID_DEPLOYMENT", `Invalid deployment configuration ${deploymentConfig}: ${err.toString()}`);
}
this.deploymentFile = deploymentConfig;
return deploymentModel;
}
/**
* Check if a deployment exists for this application
* This method cannot be called for a packaged application
* as we do not keep deployments files when deployed
*
* @param deploymentName
*/
hasDeployment(deploymentName) {
return fs.existsSync(path.join(this.appPath, "deployments", deploymentName + ".json"));
}
}
__decorate([
Cache()
], SourceApplication.prototype, "getGitInformation", null);
/**
* Used to generate module
* We do not want to load any module, we only compile the sources and then analyze
* to generate the webda.module.json
*/
export class BuildSourceApplication extends SourceApplication {
constructor() {
super(...arguments);
/**
* Module has been generated
*/
this.moduleReady = false;
}
/**
* @returns
*/
filterModule(file) {
return this.moduleReady && super.filterModule(file);
}
/**
* Override to empty if moduleReady is false
* @returns
*/
getModulesCache() {
if (!this.moduleReady) {
return {};
}
// @ts-ignore
const cacheModules = process.webdaModules || {};
// @ts-ignore
process.webdaModules ?? (process.webdaModules = cacheModules);
return cacheModules;
}
/**
* @override
*/
async generateModule() {
if (!(await super.generateModule())) {
return false;
}
// Module is generated
this.moduleReady = true;
// Reload all modules now
this.mergeModules(this.baseConfiguration);
await this.loadModule(this.baseConfiguration.cachedModules);
return true;
}
}
//# sourceMappingURL=sourceapplication.js.map