@cap-js-community/sap-afc-sdk
Version:
SAP Advanced Financial Closing SDK for CDS
345 lines (320 loc) • 10.9 kB
JavaScript
/* eslint-disable no-console */
;
const fs = require("fs");
const commander = require("commander");
const path = require("path");
const shelljs = require("shelljs");
const YAML = require("yaml");
const { projectName, adjustYAMLAllDocuments, copyFileAdjusted, derivePackageName } = require("../common/util");
const config = require("../config.json");
const { isNode, adjustJSON, adjustYAMLDocument, adjustXML } = require("../common/util");
const Version = require(path.join(__dirname, "../../package.json")).version;
const Profile = {
Default: "default",
Basic: "basic",
};
const Runtime = {
Node: "node",
Java: "java",
};
const Dependencies = {
Node: [],
Java: [
{
groupId: "com.github.capjscommunity",
artifactId: "sap-afc-sdk",
version: Version,
},
{
groupId: "org.springframework.security",
artifactId: "spring-security-test",
version: "6.5.5",
scope: "test",
},
],
};
module.exports = {
register: function (program) {
return program
.command("init")
.description("Initialize project for target platform")
.addArgument(
new commander.Argument("[target]", `Initialize project for target platform (${config.targets.join(", ")})`)
.choices(config.targets)
.default(config.defaults.target),
)
.addOption(
new commander.Option(
"-a, --add <features>",
"Add one or more features to the project (comma-separated list)",
).choices(["app", "broker", "http", "mock", "sample", "stub", "test"]),
)
.addOption(
new commander.Option("-p, --profile <profile>", "Initialization profile (default)").choices([
"default",
"basic",
]),
)
.option("-n, --node", "Node flavor enforced")
.option("-j, --java", "Java flavor enforced")
.addHelpText(
"afterAll",
`
Features:
app \t\t\t - add app files
broker \t\t - expose a broker service
http \t\t\t - add .http files
mock \t\t\t - mock job processing
sample \t\t - add sample data
stub \t\t\t - add stub implementation
test \t\t\t - add test
Examples:
afc init cf
afc init kyma
afc init cf --add app,broker,sample,http
afc init kyma --add app,broker,sample,http
`,
);
},
handle: function (target) {
const name = projectName();
if (!name) {
console.log(`CDS project not found`);
return false;
}
console.log(`Initializing project`);
let success = module.exports.process(target, this.opts());
if (success) {
const options = this.opts();
if (options.add) {
const features = options.add.split(",").map((f) => f.trim());
if (features.length > 0) {
const addCommand = require("./add");
success = addCommand.process(features, {});
}
}
}
if (success) {
console.log("Successfully initialized project.");
} else {
// eslint-disable-next-line n/no-process-exit
process.exit(-1);
}
},
process: function (target, options) {
try {
target ||= config.defaults.target;
const runtime = isNode(options) ? Runtime.Node : Runtime.Java;
const profile = options?.profile ?? Profile.Default;
processBefore(runtime, target, profile);
if (isNode(options)) {
processNode(target, profile);
} else {
processJava(target, profile);
}
processAfter(runtime, target, profile);
return true;
} catch (err) {
console.error("Project initialization failed: ", err.message);
}
return false;
},
};
function processBefore(runtime, target, profile) {
// CF
adjustYAMLDocument("mta.yaml", (yaml) => {
for (const resource of yaml.get("resources").items) {
if (resource.getIn(["parameters", "service"]) === "xsuaa") {
resource.setIn(["parameters", "service-plan"], "application");
}
}
return yaml;
});
// Kyma
adjustYAMLDocument("chart/values.yaml", (yaml) => {
if (yaml.getIn(["xsuaa", "servicePlanName"])) {
yaml.setIn(["xsuaa", "servicePlanName"], "application");
}
return yaml;
});
// CDS add
const excludes = (config.excludes[runtime] || []).concat(config.excludes[target] || []);
const features = config.features[profile].common
.concat(config.features[profile][runtime])
.concat(config.features[profile][target])
.filter((feature) => !excludes.includes(feature));
if (features.length > 0) {
shelljs.exec(`cds add ${features.join(",")} ${config.options.cds}`);
shelljs.exec("npm install");
}
}
function processNode() {
// Project
adjustJSON("package.json", (json) => {
if (
(process.env.APPROUTER_URL && !json.cds?.requires?.["sap-afc-sdk"]?.["[production]"]?.endpoints?.approuter) ||
(process.env.SERVER_URL && !json.cds?.requires?.["sap-afc-sdk"]?.["[production]"]?.endpoints?.server)
) {
json.cds ??= {};
json.cds.requires ??= {};
json.cds.requires["sap-afc-sdk"] ??= {};
json.cds.requires["sap-afc-sdk"]["[production]"] ??= {};
json.cds.requires["sap-afc-sdk"]["[production]"].endpoints ??= {};
if (process.env.APPROUTER_URL && !json.cds.requires["sap-afc-sdk"]["[production]"].endpoints.approuter) {
json.cds.requires["sap-afc-sdk"]["[production]"].endpoints.approuter = process.env.APPROUTER_URL;
}
if (process.env.SERVER_URL && !json.cds.requires["sap-afc-sdk"]["[production]"].endpoints.server) {
json.cds.requires["sap-afc-sdk"]["[production]"].endpoints.server = process.env.SERVER_URL;
}
}
if (json.cds?.server?.index === undefined) {
json.cds ??= {};
json.cds.server ??= {};
json.cds.server.index = true;
}
});
}
function processJava() {
// cdsrc
const cdsrc = adjustJSON(".cdsrc.json", (json) => {
if (json.requires?.queue?.kind !== "persistent-queue") {
json.requires ??= {};
json.requires.queue ??= {};
json.requires.queue.kind = "persistent-queue";
}
});
// Project
adjustJSON("package.json", (json) => {
json.cds ??= {};
json.cds.requires ??= {};
json.cds.requires["event-queue"] = false;
if (!cdsrc) {
if (json.cds?.requires?.queue?.kind !== "persistent-queue") {
json.cds.requires.queue ??= {};
json.cds.requires.queue.kind = "persistent-queue";
}
}
if (!json.scripts?.postinstall) {
json.scripts ??= {};
json.scripts.postinstall = "afc update";
} else if (!json.scripts.postinstall.includes("afc update")) {
json.scripts.postinstall += " && afc update";
}
});
// POM
adjustXML("srv/pom.xml", (xml) => {
if (!xml.project.dependencies) {
xml.project.dependencies = [{}];
}
for (const dependency of Dependencies.Java) {
if (
!xml.project.dependencies[0].dependency.find(
(dep) => dep.groupId[0] === dependency.groupId && dep.artifactId[0] === dependency.artifactId,
)
) {
xml.project.dependencies[0].dependency.push(dependency);
}
}
return xml;
});
// Application
adjustYAMLAllDocuments("srv/src/main/resources/application.yaml", (yamls) => {
let yaml = yamls.find((yaml) => yaml.getIn(["spring", "config.activate.on-profile"]) === "cloud");
if (!yaml) {
yaml = new YAML.Document();
yaml.setIn(["spring", "config.activate.on-profile"], "cloud");
yamls.unshift(yaml);
}
if (yaml.getIn(["sap-afc-sdk", "ui", "enabled"]) === undefined) {
yaml.setIn(["sap-afc-sdk", "ui", "enabled"], true);
}
if (
(process.env.APPROUTER_URL && !yaml.getIn(["sap-afc-sdk", "endpoints", "approuter"])) ||
(process.env.SERVER_URL && !yaml.getIn(["sap-afc-sdk", "endpoints", "server"]))
) {
if (!yaml.getIn(["sap-afc-sdk", "endpoints"])) {
yaml.setIn(["sap-afc-sdk", "endpoints"], new YAML.YAMLMap());
}
if (process.env.APPROUTER_URL && !yaml.getIn(["sap-afc-sdk", "endpoints", "approuter"])) {
yaml.setIn(["sap-afc-sdk", "endpoints", "approuter"], process.env.APPROUTER_URL);
}
if (process.env.SERVER_URL && !yaml.getIn(["sap-afc-sdk", "endpoints", "server"])) {
yaml.setIn(["sap-afc-sdk", "endpoints", "server"], process.env.SERVER_URL);
}
}
yaml = yamls.find((yaml) => !yaml.getIn(["spring", "config.activate.on-profile"]));
if (!yaml) {
yaml = new YAML.Document();
yamls.unshift(yaml);
}
if (yaml.getIn(["cds", "index-page", "enabled"]) == null) {
yaml.setIn(["cds", "index-page", "enabled"], true);
}
if (!yaml.get("springdoc")) {
yaml.set("springdoc", {
"packages-to-scan": ["com.github.capjscommunity.sapafcsdk.scheduling.controllers"],
"swagger-ui": {
path: "/api-docs/api/job-scheduling/v1",
},
});
}
if (!yaml.getIn(["sap-afc-sdk", "broker", "enabled"])) {
yaml.setIn(["sap-afc-sdk", "broker", "enabled"], false);
}
if (!yaml.getIn(["sap-afc-sdk", "syncJob", "cron"])) {
yaml.setIn(["sap-afc-sdk", "syncJob", "cron"], "0 */1 * * * *");
}
return yamls;
});
const packageName = derivePackageName(projectName());
copyFileAdjusted(
path.join(__dirname, "..", "templates/java/ApplicationConfig.java"),
path.join(process.cwd(), `srv/src/main/java/customer/${packageName}/ApplicationConfig.java`),
(content) => {
return content.replace("package customer;", `package customer.${packageName};`);
},
);
// TODO: Remove (cap/issues/18263)
const sourcePath = path.resolve(__dirname, "../../db/data");
const targetPath = path.resolve(process.cwd(), "db/csv");
if (fs.existsSync(targetPath)) {
fs.rmSync(targetPath, { recursive: true });
}
fs.cpSync(sourcePath, targetPath, { recursive: true });
}
function processAfter() {
// CF
adjustYAMLDocument("mta.yaml", (yaml) => {
for (const resource of yaml.get("resources").items) {
if (resource.getIn(["parameters", "service"]) === "xsuaa") {
resource.setIn(["parameters", "service-plan"], "broker");
}
}
return yaml;
});
// Kyma
const repository = process.env.CONTAINER_REPOSITORY;
adjustYAMLDocument("chart/values.yaml", (yaml) => {
if (process.env.GLOBAL_DOMAIN) {
yaml.setIn(["global", "domain"], process.env.GLOBAL_DOMAIN);
}
if (repository) {
yaml.setIn(["global", "image", "registry"], repository);
}
yaml.setIn(["srv", "expose", "enabled"], true);
if (yaml.getIn(["xsuaa", "servicePlanName"])) {
yaml.setIn(["xsuaa", "servicePlanName"], "broker");
}
return yaml;
});
adjustYAMLDocument("containerize.yaml", (yaml) => {
if (repository) {
yaml.set("repository", repository);
}
return yaml;
});
// Approuter
adjustJSON("app/router/xs-app.json", (json) => {
json.websockets = { enabled: true };
});
}