singularci
Version:
SingularCI is a DSL transpiler used to generate CI/CD configuration files for existing CI platforms
187 lines • 9.01 kB
JavaScript
"use strict";
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;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GitHubConfigGenerator = void 0;
const yaml_1 = __importDefault(require("yaml"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const tasks_1 = require("./tasks");
const typedi_1 = require("typedi");
const DSLParser_1 = __importDefault(require("./../../Parser/DSLParser"));
const TaskEnum_1 = require("../../SemanticModel/Tasks/TaskEnum");
let GitHubConfigGenerator = class GitHubConfigGenerator {
constructor(parser) {
this.generateConfig = () => {
if (!this.shouldGenerate())
return;
this.pipeline = this.parser.parse();
// Generate Folders and files
this.createFolderStructure();
this.buildSecrets();
this.buildTriggers();
this.buildStages();
this.writeToFile();
};
this.writeToFile = () => {
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), ".github/workflows/workflow.yml"), yaml_1.default.stringify(this.configObject), "utf-8");
};
this.createFolderStructure = () => {
if (fs_1.default.existsSync(path_1.default.join(process.cwd(), ".github"))) {
fs_1.default.rmSync(path_1.default.join(process.cwd(), ".github"), { recursive: true });
}
fs_1.default.mkdirSync(path_1.default.join(process.cwd(), ".github"));
fs_1.default.mkdirSync(path_1.default.join(process.cwd(), ".github/workflows"));
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), ".github/workflows/workflow.yml"), "", "utf-8");
};
this.buildTriggers = () => {
const isPushSet = this.pipeline.getTrigger().getTypes().includes('push');
const isPullRequestSet = this.pipeline.getTrigger().getTypes().includes('pull_request');
const onObject = {};
const triggerObject = {
on: onObject
};
if (isPushSet) {
const pushObject = {
branches: [...this.pipeline.getTrigger().getBranches()]
};
triggerObject.on.push = pushObject;
}
if (isPullRequestSet) {
const pullRequestObject = {
branches: [...this.pipeline.getTrigger().getBranches()]
};
triggerObject.on.pull_request = pullRequestObject;
}
Object.assign(this.configObject, triggerObject);
};
this.buildSecrets = () => {
this.pipeline = this.changeSecretsSyntax(this.pipeline);
};
this.changeSecretsSyntax = (obj) => {
if (typeof obj === 'object') {
// iterating over the object using for..in
for (const key in obj) {
//checking if the current value is an object itself
if (typeof obj[key] === 'object') {
// if so then again calling the same function
this.changeSecretsSyntax(obj[key]);
}
else {
// else getting the value and replacing single { with {{ and so on
if (obj[key] !== undefined && isNaN(obj[key])) {
const secrets = obj[key].match(/\$\{(secrets\.)[a-zA-Z][^{}]+\}/gm);
if (secrets) {
for (let i = 0; i < secrets.length; i++) {
const newValue = obj[key].replace(secrets[i], "${{ " + secrets[i].replace("${", "").replace("}", "") + " }}");
obj[key] = newValue;
}
}
}
}
}
}
return obj;
};
this.buildStages = () => {
const StagesArray = {};
const stagesObject = {
jobs: StagesArray
};
for (const stage of this.pipeline.getStages()) {
const builtStage = this.buildStage(stage);
const stageId = this.generateStageId(this.sanitizeJobName(stage.getName()));
stagesObject.jobs[stageId] = builtStage;
}
Object.assign(this.configObject, stagesObject);
};
this.generateStageId = (name) => {
const str = "" + name;
return str.replace(' ', '_').toLowerCase();
};
this.buildStage = (stage) => {
const stageObject = {
steps: this.buildJobs(stage.getJobs())
};
Object.assign(stageObject, this.setRuntimeContainer(stage));
if (stage.getNeeds().length > 0) {
stageObject.needs = stage.getNeeds();
}
return stageObject;
};
this.buildJobs = (jobs) => {
const resultArr = [];
for (const job of jobs) {
const tasks = job.getTasks();
const checkoutTasks = tasks.filter((task) => task.getType() === TaskEnum_1.TaskType.Checkout);
let checkoutRepoName = "";
if (checkoutTasks.length > 1) {
throw new Error("Only one checkout is allowed per job");
}
if (checkoutTasks.length === 1) {
checkoutRepoName = checkoutTasks[0].getRepositoryName();
}
for (const task of tasks) {
const tempTasks = [];
if (task.getType() === TaskEnum_1.TaskType.BuildDockerImage) {
tempTasks.push(...(0, tasks_1.generateBuildDockerImageTask)(task));
}
if (task.getType() === TaskEnum_1.TaskType.Checkout) {
tempTasks.push((0, tasks_1.generateCheckoutTask)(task));
}
if (task.getType() === TaskEnum_1.TaskType.Run) {
const tempObj = (0, tasks_1.generateRunTask)(task);
if (checkoutRepoName) {
// @ts-ignore
tempObj["working-directory"] = checkoutRepoName;
}
tempTasks.push(tempObj);
}
if (task.getType() === TaskEnum_1.TaskType.Checkout) {
resultArr.unshift(...tempTasks);
}
else {
resultArr.push(...tempTasks);
}
}
}
return resultArr;
};
this.setRuntimeContainer = (stage) => {
const runsOn = stage.getRunsOn();
if (runsOn != "ubuntu-latest" && runsOn != "windows-latest") {
return { 'runs-on': "ubuntu-latest", 'container': runsOn };
}
return { 'runs-on': runsOn };
};
this.sanitizeJobName = (name) => {
return name.replaceAll(' ', '_');
};
this.parser = parser;
this.pipeline = parser.parse();
this.configObject = {};
}
shouldGenerate() {
return this.pipeline != undefined && this.pipeline.getPlatformTargets().getTargets().includes('GitHub');
}
};
GitHubConfigGenerator = __decorate([
(0, typedi_1.Service)({ id: "GitHubConfigGenerator" }),
__param(0, (0, typedi_1.Inject)('dslparser')),
__metadata("design:paramtypes", [DSLParser_1.default])
], GitHubConfigGenerator);
exports.GitHubConfigGenerator = GitHubConfigGenerator;
//# sourceMappingURL=index.js.map