cispacempt-v2 0.1.3 → 0.1.5
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 +64 -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,69 @@ 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
|
-
|
|
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();
|
|
120
|
+
console.log(isFileSystemPath);
|
|
158
121
|
|
|
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
|
-
}
|
|
122
|
+
const stageExecuted = {}; // Track executed stages
|
|
180
123
|
|
|
181
124
|
for (const stage of stages) {
|
|
182
|
-
extensionSystem.runPreExecution(stage.name);
|
|
125
|
+
extensionSystem.runPreExecution(stage.name);
|
|
183
126
|
|
|
184
127
|
if (stage.scripts && Array.isArray(stage.scripts)) {
|
|
185
|
-
|
|
186
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
downloadFiles(fileSystem, tempDir);
|
|
128
|
+
let workingDir;
|
|
190
129
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
130
|
+
if (isFileSystemPath) {
|
|
131
|
+
// Use the existing directory directly
|
|
132
|
+
workingDir = fileSystem;
|
|
133
|
+
} else {
|
|
134
|
+
// Write files to tempDir
|
|
135
|
+
if (!fs.existsSync(tempDir)) {
|
|
136
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
137
|
+
}
|
|
138
|
+
downloadFiles(fileSystem, tempDir);
|
|
139
|
+
workingDir = tempDir;
|
|
140
|
+
}
|
|
199
141
|
|
|
200
142
|
await new Promise((resolve) => {
|
|
201
143
|
(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
144
|
const results = [];
|
|
209
145
|
|
|
146
|
+
if (!stageExecuted[stage.name]) {
|
|
147
|
+
onOutput(`[${stage.name}]\n`);
|
|
148
|
+
stageExecuted[stage.name] = true;
|
|
149
|
+
}
|
|
150
|
+
|
|
210
151
|
for (const command of commands) {
|
|
211
152
|
const resolvedCommand = substituteEnvVariables(command, ciScript.env || {});
|
|
212
153
|
|
|
213
|
-
await new Promise(
|
|
154
|
+
await new Promise((res) => {
|
|
214
155
|
const commandToRun = resolvedCommand;
|
|
215
|
-
const child = spawn(commandToRun, { cwd:
|
|
156
|
+
const child = spawn(commandToRun, { cwd: workingDir, shell: true });
|
|
216
157
|
let stdoutData = "";
|
|
217
158
|
let stderrData = "";
|
|
218
159
|
|
|
219
|
-
|
|
220
|
-
|
|
160
|
+
onOutput(`$ ${resolvedCommand}\n`);
|
|
161
|
+
|
|
162
|
+
child.stdout.on("data", (data) => {
|
|
163
|
+
const text = data.toString();
|
|
164
|
+
stdoutData += text;
|
|
165
|
+
onOutput(text);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
child.stderr.on("data", (data) => {
|
|
169
|
+
const text = data.toString();
|
|
170
|
+
onOutput(`${commandToRun}\n${text}`);
|
|
171
|
+
});
|
|
221
172
|
|
|
222
173
|
child.on("close", (code) => {
|
|
223
174
|
results.push({
|
|
@@ -227,27 +178,28 @@ module.exports = {
|
|
|
227
178
|
exitCode: code,
|
|
228
179
|
error: code === 0 ? null : `Command failed with exit code ${code}`,
|
|
229
180
|
});
|
|
181
|
+
|
|
182
|
+
if (code !== 0) onOutput(`[!] Exit code ${code}\n`);
|
|
230
183
|
res();
|
|
231
184
|
});
|
|
232
185
|
});
|
|
233
186
|
|
|
234
187
|
if (results.at(-1).exitCode !== 0) break;
|
|
235
188
|
}
|
|
189
|
+
|
|
236
190
|
callback(results);
|
|
237
|
-
extensionSystem.runPostExecution(stage.name, results);
|
|
191
|
+
extensionSystem.runPostExecution(stage.name, results);
|
|
238
192
|
resolve();
|
|
239
193
|
})(stage.scripts, (results) => {
|
|
240
|
-
let output =
|
|
194
|
+
let output = "";
|
|
241
195
|
|
|
242
196
|
results.forEach((result) => {
|
|
243
197
|
output += `$ ${result.command}\n`;
|
|
244
198
|
if (result.error) {
|
|
245
199
|
output += `Error: ${result.error}\n`;
|
|
246
200
|
output += `${result.stderr ? result.stderr : ''}\n`;
|
|
247
|
-
!errorIn.includes(stage.name) ? errorIn.push(stage.name) : null;
|
|
248
201
|
} else {
|
|
249
202
|
output += `${result.stdout ? result.stdout : ''}\n`;
|
|
250
|
-
!successIn.includes(stage.name) ? successIn.push(stage.name) : null;
|
|
251
203
|
}
|
|
252
204
|
|
|
253
205
|
if (result.exitCode !== 0) {
|
|
@@ -261,30 +213,27 @@ module.exports = {
|
|
|
261
213
|
}
|
|
262
214
|
}
|
|
263
215
|
|
|
264
|
-
|
|
216
|
+
// Only parse directory JSON if we created tempDir (fileSystem not a path)
|
|
217
|
+
const fileSysJson = isFileSystemPath ? null : parseDirectoryToJson(tempDir);
|
|
218
|
+
|
|
265
219
|
const finalResultEndTime = Date.now();
|
|
266
220
|
timeTaken = convertMsToSec(finalResultEndTime - startTime);
|
|
267
221
|
const cpuEnd = getCPUUsageSnapshot();
|
|
268
222
|
|
|
269
223
|
const ciLogResult = {
|
|
270
224
|
output: finalResult.join(''),
|
|
271
|
-
timestamp:
|
|
272
|
-
fileSys:
|
|
225
|
+
timestamp: new Date().toString(),
|
|
226
|
+
...(returnJsonFs && { fileSys: fileSysJson }),
|
|
273
227
|
ci_duration: timeTaken,
|
|
274
228
|
exitCode: combinedExitCode,
|
|
275
229
|
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
230
|
};
|
|
284
231
|
|
|
285
|
-
|
|
232
|
+
if (!isFileSystemPath) {
|
|
233
|
+
cleanUpAndRespond(tempDir);
|
|
234
|
+
}
|
|
286
235
|
|
|
287
|
-
extensionSystem.runEnd(ciLogResult, stages.map(stage => stage.name), finalResult);
|
|
236
|
+
extensionSystem.runEnd(ciLogResult, stages.map(stage => stage.name), finalResult);
|
|
288
237
|
|
|
289
238
|
return ciLogResult;
|
|
290
239
|
},
|