cispacempt-v2 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/index.js +63 -115
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -2,7 +2,6 @@ const path = require("path"),
|
|
|
2
2
|
os = require("os"),
|
|
3
3
|
fs = require("fs"),
|
|
4
4
|
{ spawn } = require("child_process"),
|
|
5
|
-
yaml = require("js-yaml"),
|
|
6
5
|
getCPUUsageSnapshot = function () {
|
|
7
6
|
const cpus = os.cpus();
|
|
8
7
|
return cpus.map(cpu => ({ ...cpu.times }));
|
|
@@ -84,40 +83,20 @@ const path = require("path"),
|
|
|
84
83
|
fs.writeFileSync(filePath, fileSystem[file]);
|
|
85
84
|
}
|
|
86
85
|
});
|
|
87
|
-
},
|
|
88
|
-
detectAvailableProotOSID = () => {
|
|
89
|
-
const baseDir = path.resolve(__dirname); // o __dirname donde esté el código
|
|
90
|
-
const entries = fs.readdirSync(baseDir, { withFileTypes: true });
|
|
91
|
-
|
|
92
|
-
for (const entry of entries) {
|
|
93
|
-
if (entry.isDirectory() && entry.name.startsWith("rootfs-")) {
|
|
94
|
-
const osReleasePath = path.join(baseDir, entry.name, "etc", "os-release");
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
const content = fs.readFileSync(osReleasePath, "utf8");
|
|
98
|
-
const match = content.match(/^ID="?([\w\-]+)"?/m);
|
|
99
|
-
|
|
100
|
-
if (match) {
|
|
101
|
-
return {
|
|
102
|
-
id: match[1], // ej. "debian", "alpine"
|
|
103
|
-
rootfsPath: path.join(baseDir, entry.name), // ruta completa
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
} catch (_) {
|
|
107
|
-
// No es un rootfs válido, seguimos con el siguiente
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return null; // No se encontró ninguno válido
|
|
113
86
|
}, { extensionSystem } = require("./extension");
|
|
114
|
-
|
|
115
|
-
// Export as a Node JS module
|
|
116
87
|
module.exports = {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
88
|
+
run: async function (
|
|
89
|
+
ciScript, // the script to run
|
|
90
|
+
fileSystem, // a path or a json representation of your file system (kinda like {"app.js":"console.log('Hi!');"})
|
|
91
|
+
tmp = true, // self explanatory; run in a temporary environment
|
|
92
|
+
returnJsonFs = false, // if you want a json representation of your fs (dont use this if your working on binaries)
|
|
93
|
+
repoName = (
|
|
94
|
+
require('crypto')
|
|
95
|
+
.randomBytes(16)
|
|
96
|
+
.toString('hex')
|
|
97
|
+
), // to name the tmp dir
|
|
98
|
+
onOutput = () => { } // for live outputs
|
|
99
|
+
) {
|
|
121
100
|
let finalResult = [];
|
|
122
101
|
let timeTaken;
|
|
123
102
|
let combinedExitCode = 0;
|
|
@@ -127,97 +106,68 @@ module.exports = {
|
|
|
127
106
|
const convertMsToSec = (ms) => (ms / 1000).toFixed(2);
|
|
128
107
|
|
|
129
108
|
const stages = Object.entries(ciScript.stages).map(([name, data]) => ({ name, ...data }));
|
|
130
|
-
const tempDir = path.join(__dirname, tmp
|
|
109
|
+
const tempDir = path.join(__dirname, tmp === true ? "tmp/" + repoName : repoName);
|
|
131
110
|
|
|
111
|
+
// Helper to substitute env variables in commands
|
|
132
112
|
const substituteEnvVariables = (command, env) => {
|
|
133
113
|
return command.replace(/\${\[(\w+)\]}/g, (_, varName) => {
|
|
134
114
|
return env[varName] ?? '';
|
|
135
115
|
});
|
|
136
116
|
};
|
|
137
117
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
let currentMap = fileSystem;
|
|
141
|
-
|
|
142
|
-
for (let i = 0; i < pathParts.length; i++) {
|
|
143
|
-
const part = pathParts[i];
|
|
144
|
-
|
|
145
|
-
if (currentMap[part]) {
|
|
146
|
-
if (typeof currentMap[part] === "object") {
|
|
147
|
-
currentMap = currentMap[part];
|
|
148
|
-
} else {
|
|
149
|
-
return currentMap[part]; // Return the found file if it exists
|
|
150
|
-
}
|
|
151
|
-
} else {
|
|
152
|
-
return null; // Return null if not found at all
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return null; // Return null if path doesn't exist
|
|
157
|
-
}
|
|
118
|
+
// Detect if fileSystem is a directory path string
|
|
119
|
+
const isFileSystemPath = typeof fileSystem === 'string' && fs.existsSync(fileSystem) && fs.statSync(fileSystem).isDirectory();
|
|
158
120
|
|
|
159
|
-
|
|
160
|
-
for (const includePath of ciScript.include) {
|
|
161
|
-
const templateContent = findFileInMap(fileSystem, includePath);
|
|
162
|
-
if (!templateContent) {
|
|
163
|
-
console.warn(`Included file '${includePath}' not found`);
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const includedYaml = yaml.load(templateContent);
|
|
168
|
-
|
|
169
|
-
// Merge included content
|
|
170
|
-
ciScript.stages = {
|
|
171
|
-
...(includedYaml.stages || {}),
|
|
172
|
-
...(ciScript.stages || {})
|
|
173
|
-
};
|
|
174
|
-
ciScript.env = {
|
|
175
|
-
...(includedYaml.env || {}),
|
|
176
|
-
...(ciScript.env || {}),
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
}
|
|
121
|
+
const stageExecuted = {}; // Track executed stages
|
|
180
122
|
|
|
181
123
|
for (const stage of stages) {
|
|
182
|
-
extensionSystem.runPreExecution(stage.name);
|
|
124
|
+
extensionSystem.runPreExecution(stage.name);
|
|
183
125
|
|
|
184
126
|
if (stage.scripts && Array.isArray(stage.scripts)) {
|
|
185
|
-
|
|
186
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
downloadFiles(fileSystem, tempDir);
|
|
127
|
+
let workingDir;
|
|
190
128
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
129
|
+
if (isFileSystemPath) {
|
|
130
|
+
// Use the existing directory directly
|
|
131
|
+
workingDir = fileSystem;
|
|
132
|
+
} else {
|
|
133
|
+
// Write files to tempDir
|
|
134
|
+
if (!fs.existsSync(tempDir)) {
|
|
135
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
136
|
+
}
|
|
137
|
+
downloadFiles(fileSystem, tempDir);
|
|
138
|
+
workingDir = tempDir;
|
|
139
|
+
}
|
|
199
140
|
|
|
200
141
|
await new Promise((resolve) => {
|
|
201
142
|
(async function (commands, callback) {
|
|
202
|
-
for (const fileName of Object.keys(installCommands)) {
|
|
203
|
-
const foundKey = Object.keys(parseDirectoryToJson(tempDir)).find(key => key.includes(fileName));
|
|
204
|
-
if (foundKey && !commands.includes(installCommands[fileName])) {
|
|
205
|
-
commands.push(installCommands[fileName]);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
143
|
const results = [];
|
|
209
144
|
|
|
145
|
+
if (!stageExecuted[stage.name]) {
|
|
146
|
+
onOutput(`[${stage.name}]\n`);
|
|
147
|
+
stageExecuted[stage.name] = true;
|
|
148
|
+
}
|
|
149
|
+
|
|
210
150
|
for (const command of commands) {
|
|
211
151
|
const resolvedCommand = substituteEnvVariables(command, ciScript.env || {});
|
|
212
152
|
|
|
213
|
-
await new Promise(
|
|
153
|
+
await new Promise((res) => {
|
|
214
154
|
const commandToRun = resolvedCommand;
|
|
215
|
-
const child = spawn(commandToRun, { cwd:
|
|
155
|
+
const child = spawn(commandToRun, { cwd: workingDir, shell: true });
|
|
216
156
|
let stdoutData = "";
|
|
217
157
|
let stderrData = "";
|
|
218
158
|
|
|
219
|
-
|
|
220
|
-
|
|
159
|
+
onOutput(`$ ${resolvedCommand}\n`);
|
|
160
|
+
|
|
161
|
+
child.stdout.on("data", (data) => {
|
|
162
|
+
const text = data.toString();
|
|
163
|
+
stdoutData += text;
|
|
164
|
+
onOutput(text);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
child.stderr.on("data", (data) => {
|
|
168
|
+
const text = data.toString();
|
|
169
|
+
onOutput(`${commandToRun}\n${text}`);
|
|
170
|
+
});
|
|
221
171
|
|
|
222
172
|
child.on("close", (code) => {
|
|
223
173
|
results.push({
|
|
@@ -227,27 +177,28 @@ module.exports = {
|
|
|
227
177
|
exitCode: code,
|
|
228
178
|
error: code === 0 ? null : `Command failed with exit code ${code}`,
|
|
229
179
|
});
|
|
180
|
+
|
|
181
|
+
if (code !== 0) onOutput(`[!] Exit code ${code}\n`);
|
|
230
182
|
res();
|
|
231
183
|
});
|
|
232
184
|
});
|
|
233
185
|
|
|
234
186
|
if (results.at(-1).exitCode !== 0) break;
|
|
235
187
|
}
|
|
188
|
+
|
|
236
189
|
callback(results);
|
|
237
|
-
extensionSystem.runPostExecution(stage.name, results);
|
|
190
|
+
extensionSystem.runPostExecution(stage.name, results);
|
|
238
191
|
resolve();
|
|
239
192
|
})(stage.scripts, (results) => {
|
|
240
|
-
let output =
|
|
193
|
+
let output = "";
|
|
241
194
|
|
|
242
195
|
results.forEach((result) => {
|
|
243
196
|
output += `$ ${result.command}\n`;
|
|
244
197
|
if (result.error) {
|
|
245
198
|
output += `Error: ${result.error}\n`;
|
|
246
199
|
output += `${result.stderr ? result.stderr : ''}\n`;
|
|
247
|
-
!errorIn.includes(stage.name) ? errorIn.push(stage.name) : null;
|
|
248
200
|
} else {
|
|
249
201
|
output += `${result.stdout ? result.stdout : ''}\n`;
|
|
250
|
-
!successIn.includes(stage.name) ? successIn.push(stage.name) : null;
|
|
251
202
|
}
|
|
252
203
|
|
|
253
204
|
if (result.exitCode !== 0) {
|
|
@@ -261,30 +212,27 @@ module.exports = {
|
|
|
261
212
|
}
|
|
262
213
|
}
|
|
263
214
|
|
|
264
|
-
|
|
215
|
+
// Only parse directory JSON if we created tempDir (fileSystem not a path)
|
|
216
|
+
const fileSysJson = isFileSystemPath ? null : parseDirectoryToJson(tempDir);
|
|
217
|
+
|
|
265
218
|
const finalResultEndTime = Date.now();
|
|
266
219
|
timeTaken = convertMsToSec(finalResultEndTime - startTime);
|
|
267
220
|
const cpuEnd = getCPUUsageSnapshot();
|
|
268
221
|
|
|
269
222
|
const ciLogResult = {
|
|
270
223
|
output: finalResult.join(''),
|
|
271
|
-
timestamp:
|
|
272
|
-
fileSys:
|
|
224
|
+
timestamp: new Date().toString(),
|
|
225
|
+
...(returnJsonFs && { fileSys: fileSysJson }),
|
|
273
226
|
ci_duration: timeTaken,
|
|
274
227
|
exitCode: combinedExitCode,
|
|
275
228
|
cpu_usage: calculateCPUUsage(cpuStart, cpuEnd),
|
|
276
|
-
os: {
|
|
277
|
-
name: os.platform(),
|
|
278
|
-
version: os.release(),
|
|
279
|
-
arch: os.arch(),
|
|
280
|
-
},
|
|
281
|
-
errorIn: errorIn.length > 0 ? errorIn : null,
|
|
282
|
-
successIn: successIn.length > 0 ? successIn : null,
|
|
283
229
|
};
|
|
284
230
|
|
|
285
|
-
|
|
231
|
+
if (!isFileSystemPath) {
|
|
232
|
+
cleanUpAndRespond(tempDir);
|
|
233
|
+
}
|
|
286
234
|
|
|
287
|
-
extensionSystem.runEnd(ciLogResult, stages.map(stage => stage.name), finalResult);
|
|
235
|
+
extensionSystem.runEnd(ciLogResult, stages.map(stage => stage.name), finalResult);
|
|
288
236
|
|
|
289
237
|
return ciLogResult;
|
|
290
238
|
},
|