Skip to content

Commit

Permalink
feat: add support for absolute path for options that makes sense
Browse files Browse the repository at this point in the history
  • Loading branch information
ANGkeith committed Oct 3, 2024
1 parent 431c2a0 commit 4ec2036
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 102 deletions.
38 changes: 30 additions & 8 deletions src/argv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ async function gitRootPath () {
return stdout;
}

const generateGitIgnore = (stateDir: string) => {
const gitIgnoreFilePath = path.join(stateDir, ".gitignore");
const gitIgnoreContent = "*\n!.gitignore\n";
if (!fs.existsSync(gitIgnoreFilePath)) {
fs.outputFileSync(gitIgnoreFilePath, gitIgnoreContent);
}
};

export class Argv {

private map: Map<string, any> = new Map<string, any>();
Expand All @@ -39,7 +47,7 @@ export class Argv {
const argv = new Argv(args, writeStreams);
await argv.fallbackCwd(args);

argv.injectDotenv(`${argv.home}/.gitlab-ci-local/.env`, args);
argv.injectDotenv(`${argv.home}/.env`, args);
argv.injectDotenv(`${argv.cwd}/.gitlab-ci-local-env`, args);

if (!argv.shellExecutorNoImage && argv.shellIsolation) {
Expand Down Expand Up @@ -75,23 +83,37 @@ export class Argv {
get cwd (): string {
let cwd = this.map.get("cwd") ?? ".";
assert(typeof cwd != "object", "--cwd option cannot be an array");
assert(!path.isAbsolute(cwd), "Please use relative path for the --cwd option");
cwd = path.normalize(`${process.cwd()}/${cwd}`);
cwd = cwd.replace(/\/$/, "");
assert(fs.pathExistsSync(cwd), `${cwd} is not a directory`);
if (!path.isAbsolute(cwd)) {
cwd = path.resolve(`${process.cwd()}/${cwd}`);
}
assert(fs.pathExistsSync(cwd), `--cwd (${cwd}) is not a directory`);
return cwd;
}

get file (): string {
return this.map.get("file") ?? ".gitlab-ci.yml";
let file = this.map.get("file") ?? ".gitlab-ci.yml";
if (!path.isAbsolute(file)) {
file = `${this.cwd}/${file}`;
}
assert(fs.existsSync(`${file}`), `--file (${file}) could not be found`);
return file;
}

get stateDir (): string {
return (this.map.get("stateDir") ?? ".gitlab-ci-local").replace(/\/$/, "");
let stateDir = this.map.get("stateDir") ?? ".gitlab-ci-local";
if (path.isAbsolute(stateDir)) {
// autogenerate uniqueStateDir
return `${stateDir}/${this.cwd.replaceAll("/", ".")}`;
}
stateDir = `${this.cwd}/${stateDir}`;
generateGitIgnore(stateDir);
return stateDir;
}

get home (): string {
return (this.map.get("home") ?? process.env.HOME ?? "").replace(/\/$/, "");
const home = (this.map.get("home") ?? `${process.env.HOME}/.gitlab-ci-local}`).replace(/\/$/, "");
assert(path.isAbsolute(home), `--home (${home}) must be a absolute path`);
return home;
}

get volume (): string[] {
Expand Down
10 changes: 3 additions & 7 deletions src/commander.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export class Commander {
potentialStarters = potentialStarters.filter(j => j.when !== "manual" || argv.manual.includes(j.name));
await Executor.runLoop(argv, jobs, stages, potentialStarters);
await Commander.printReport({
cwd: argv.cwd,
showTimestamps: argv.showTimestamps,
stateDir: argv.stateDir,
writeStreams: writeStreams,
Expand All @@ -39,7 +38,6 @@ export class Commander {
potentialStarters = potentialStarters.filter(j => j.stage === argv.stage);
await Executor.runLoop(argv, jobs, stages, potentialStarters);
await Commander.printReport({
cwd: argv.cwd,
showTimestamps: argv.showTimestamps,
stateDir: argv.stateDir,
writeStreams: writeStreams,
Expand Down Expand Up @@ -78,7 +76,6 @@ export class Commander {

await Executor.runLoop(argv, Array.from(jobSet), stages, starters);
await Commander.printReport({
cwd: argv.cwd,
showTimestamps: argv.showTimestamps,
stateDir: argv.stateDir,
writeStreams: writeStreams,
Expand All @@ -88,8 +85,7 @@ export class Commander {
});
}

static async printReport ({cwd, stateDir, showTimestamps, writeStreams, jobs, stages, jobNamePad}: {
cwd: string;
static async printReport ({stateDir, showTimestamps, writeStreams, jobs, stages, jobNamePad}: {
showTimestamps: boolean;
stateDir: string;
writeStreams: WriteStreams;
Expand Down Expand Up @@ -149,7 +145,7 @@ export class Commander {
const namePad = name.padEnd(jobNamePad);
const safeName = Utils.safeDockerString(name);
writeStreams.stdout(chalk`{black.bgYellowBright WARN }${renderDuration(prettyDuration)} {blueBright ${namePad}} pre_script\n`);
const outputLog = await fs.readFile(`${cwd}/${stateDir}/output/${safeName}.log`, "utf8");
const outputLog = await fs.readFile(`${stateDir}/output/${safeName}.log`, "utf8");
for (const line of outputLog.split(/\r?\n/).filter(j => !j.includes("[32m$ ")).filter(j => j !== "").slice(-3)) {
writeStreams.stdout(chalk` {yellow >} ${line}\n`);
}
Expand All @@ -170,7 +166,7 @@ export class Commander {
const namePad = name.padEnd(jobNamePad);
const safeName = Utils.safeDockerString(name);
writeStreams.stdout(chalk`{black.bgRed FAIL }${renderDuration(prettyDuration)} {blueBright ${namePad}}\n`);
const outputLog = await fs.readFile(`${cwd}/${stateDir}/output/${safeName}.log`, "utf8");
const outputLog = await fs.readFile(`${stateDir}/output/${safeName}.log`, "utf8");
for (const line of outputLog.split(/\r?\n/).filter(j => !j.includes("[32m$ ")).filter(j => j !== "").slice(-3)) {
writeStreams.stdout(chalk` {red >} ${line}\n`);
}
Expand Down
37 changes: 11 additions & 26 deletions src/handler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as yaml from "js-yaml";
import chalk from "chalk";
import path from "path";
import * as fs from "fs-extra";
import * as yargs from "yargs";
import {Commander} from "./commander";
Expand All @@ -13,35 +12,24 @@ import {Utils} from "./utils";
import {Argv} from "./argv";
import assert from "assert";

const generateGitIgnore = (cwd: string, stateDir: string) => {
const gitIgnoreFilePath = `${cwd}/${stateDir}/.gitignore`;
const gitIgnoreContent = "*\n!.gitignore\n";
if (!fs.existsSync(gitIgnoreFilePath)) {
fs.outputFileSync(gitIgnoreFilePath, gitIgnoreContent);
}
};

export async function handler (args: any, writeStreams: WriteStreams, jobs: Job[] = []) {
const argv = await Argv.build(args, writeStreams);
const cwd = argv.cwd;
const stateDir = argv.stateDir;
const file = argv.file;
let parser: Parser | null = null;

if (argv.completion) {
yargs.showCompletionScript();
return [];
}

assert(fs.existsSync(`${cwd}/${file}`), `${path.resolve(cwd)}/${file} could not be found`);

if (argv.fetchIncludes) {
await Parser.create(argv, writeStreams, 0, jobs);
return [];
}

if (argv.preview) {
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
const pipelineIid = await state.getPipelineIid(stateDir);
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs, false);
const gitlabData = parser.gitlabData;
for (const jobName of Object.keys(gitlabData)) {
Expand All @@ -55,46 +43,43 @@ export async function handler (args: any, writeStreams: WriteStreams, jobs: Job[
}
writeStreams.stdout(`---\n${yaml.dump(gitlabData, {lineWidth: 160})}`);
} else if (argv.list || argv.listAll) {
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
const pipelineIid = await state.getPipelineIid(stateDir);
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
Commander.runList(parser, writeStreams, argv.listAll);
} else if (argv.listJson) {
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
const pipelineIid = await state.getPipelineIid(stateDir);
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
Commander.runJson(parser, writeStreams);
} else if (argv.listCsv || argv.listCsvAll) {
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
const pipelineIid = await state.getPipelineIid(stateDir);
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
Commander.runCsv(parser, writeStreams, argv.listCsvAll);
} else if (argv.job.length > 0) {
assert(argv.stage === null, "You cannot use --stage when starting individual jobs");
generateGitIgnore(cwd, stateDir);
const time = process.hrtime();
if (argv.needs || argv.onlyNeeds) {
await fs.remove(`${cwd}/${stateDir}/artifacts`);
await state.incrementPipelineIid(cwd, stateDir);
await fs.remove(`${stateDir}/artifacts`);
await state.incrementPipelineIid(stateDir);
}
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
const pipelineIid = await state.getPipelineIid(stateDir);
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
await Commander.runJobs(argv, parser, writeStreams);
if (argv.needs || argv.onlyNeeds) {
writeStreams.stderr(chalk`{grey pipeline finished} in {grey ${prettyHrtime(process.hrtime(time))}}\n`);
}
} else if (argv.stage) {
generateGitIgnore(cwd, stateDir);
const time = process.hrtime();
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
const pipelineIid = await state.getPipelineIid(stateDir);
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
await Commander.runJobsInStage(argv, parser, writeStreams);
writeStreams.stderr(chalk`{grey pipeline finished} in {grey ${prettyHrtime(process.hrtime(time))}}\n`);
} else {
generateGitIgnore(cwd, stateDir);
const time = process.hrtime();
await fs.remove(`${cwd}/${stateDir}/artifacts`);
await state.incrementPipelineIid(cwd, stateDir);
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
await fs.remove(`${stateDir}/artifacts`);
await state.incrementPipelineIid(stateDir);
const pipelineIid = await state.getPipelineIid(stateDir);
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
await Commander.runPipeline(argv, parser, writeStreams);
Expand Down
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ process.on("SIGUSR2", async () => await cleanupJobResources(jobs));
})
.option("cwd", {
type: "string",
description: "Path to a current working directory",
description: "Path to the current working directory of the gitlab-ci-local executor",
requiresArg: true,
})
.option("completion", {
Expand Down Expand Up @@ -146,17 +146,17 @@ process.on("SIGUSR2", async () => await cleanupJobResources(jobs));
})
.option("state-dir", {
type: "string",
description: "Location of the .gitlab-ci-local state dir, relative to cwd, eg. (symfony/.gitlab-ci-local/)",
description: "Location of the .gitlab-ci-local state dir",
requiresArg: false,
})
.option("file", {
type: "string",
description: "Location of the .gitlab-ci.yml, relative to cwd, eg. (gitlab/.gitlab-ci.yml)",
description: "Location of the .gitlab-ci.yml",
requiresArg: false,
})
.option("home", {
type: "string",
description: "Location of the HOME .gitlab-ci-local folder ($HOME/.gitlab-ci-local/variables.yml)",
description: "Location of the HOME(gcl global config) [default: $HOME/.gitlab-ci-local]",
requiresArg: false,
})
.option("shell-isolation", {
Expand Down Expand Up @@ -275,7 +275,7 @@ process.on("SIGUSR2", async () => await cleanupJobResources(jobs));
completionFilter();
} else {
Argv.build({...yargsArgv, autoCompleting: true})
.then(argv => state.getPipelineIid(argv.cwd, argv.stateDir).then(pipelineIid => ({argv, pipelineIid})))
.then(argv => state.getPipelineIid(argv.stateDir).then(pipelineIid => ({argv, pipelineIid})))
.then(({argv, pipelineIid}) => Parser.create(argv, new WriteStreamsMock(), pipelineIid, []))
.then((parser) => {
const jobNames = [...parser.jobs.values()].filter((j) => j.when != "never").map((j) => j.name);
Expand Down
Loading

0 comments on commit 4ec2036

Please sign in to comment.