Skip to content

Commit 6708d10

Browse files
committed
feat: support absolute path for options that makes sense
1 parent 794939b commit 6708d10

17 files changed

+179
-101
lines changed

src/argv.ts

+30-8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ async function gitRootPath () {
2121
return stdout;
2222
}
2323

24+
const generateGitIgnore = (stateDir: string) => {
25+
const gitIgnoreFilePath = path.join(stateDir, ".gitignore");
26+
const gitIgnoreContent = "*\n!.gitignore\n";
27+
if (!fs.pathExistsSync(gitIgnoreFilePath)) {
28+
fs.outputFileSync(gitIgnoreFilePath, gitIgnoreContent);
29+
}
30+
};
31+
2432
export class Argv {
2533

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

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

4553
if (!argv.shellExecutorNoImage && argv.shellIsolation) {
@@ -75,23 +83,37 @@ export class Argv {
7583
get cwd (): string {
7684
let cwd = this.map.get("cwd") ?? ".";
7785
assert(typeof cwd != "object", "--cwd option cannot be an array");
78-
assert(!path.isAbsolute(cwd), "Please use relative path for the --cwd option");
79-
cwd = path.normalize(`${process.cwd()}/${cwd}`);
80-
cwd = cwd.replace(/\/$/, "");
81-
assert(fs.pathExistsSync(cwd), `${cwd} is not a directory`);
86+
if (!path.isAbsolute(cwd)) {
87+
cwd = path.resolve(`${process.cwd()}/${cwd}`);
88+
}
89+
assert(fs.pathExistsSync(cwd), `--cwd (${cwd}) is not a directory`);
8290
return cwd;
8391
}
8492

8593
get file (): string {
86-
return this.map.get("file") ?? ".gitlab-ci.yml";
94+
let file = this.map.get("file") ?? ".gitlab-ci.yml";
95+
if (!path.isAbsolute(file)) {
96+
file = `${this.cwd}/${file}`;
97+
}
98+
assert(fs.pathExistsSync(`${file}`), `--file (${file}) could not be found`);
99+
return file;
87100
}
88101

89102
get stateDir (): string {
90-
return (this.map.get("stateDir") ?? ".gitlab-ci-local").replace(/\/$/, "");
103+
let stateDir = this.map.get("stateDir") ?? ".gitlab-ci-local";
104+
if (path.isAbsolute(stateDir)) {
105+
// autogenerate uniqueStateDir
106+
return `${stateDir}/${this.cwd.replaceAll("/", ".")}`;
107+
}
108+
stateDir = `${this.cwd}/${stateDir}`;
109+
generateGitIgnore(stateDir);
110+
return stateDir;
91111
}
92112

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

97119
get volume (): string[] {

src/commander.ts

+3-7
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export class Commander {
1919
potentialStarters = potentialStarters.filter(j => j.when !== "manual" || argv.manual.includes(j.name));
2020
await Executor.runLoop(argv, jobs, stages, potentialStarters);
2121
await Commander.printReport({
22-
cwd: argv.cwd,
2322
showTimestamps: argv.showTimestamps,
2423
stateDir: argv.stateDir,
2524
writeStreams: writeStreams,
@@ -39,7 +38,6 @@ export class Commander {
3938
potentialStarters = potentialStarters.filter(j => j.stage === argv.stage);
4039
await Executor.runLoop(argv, jobs, stages, potentialStarters);
4140
await Commander.printReport({
42-
cwd: argv.cwd,
4341
showTimestamps: argv.showTimestamps,
4442
stateDir: argv.stateDir,
4543
writeStreams: writeStreams,
@@ -78,7 +76,6 @@ export class Commander {
7876

7977
await Executor.runLoop(argv, Array.from(jobSet), stages, starters);
8078
await Commander.printReport({
81-
cwd: argv.cwd,
8279
showTimestamps: argv.showTimestamps,
8380
stateDir: argv.stateDir,
8481
writeStreams: writeStreams,
@@ -88,8 +85,7 @@ export class Commander {
8885
});
8986
}
9087

91-
static async printReport ({cwd, stateDir, showTimestamps, writeStreams, jobs, stages, jobNamePad}: {
92-
cwd: string;
88+
static async printReport ({stateDir, showTimestamps, writeStreams, jobs, stages, jobNamePad}: {
9389
showTimestamps: boolean;
9490
stateDir: string;
9591
writeStreams: WriteStreams;
@@ -149,7 +145,7 @@ export class Commander {
149145
const namePad = name.padEnd(jobNamePad);
150146
const safeName = Utils.safeDockerString(name);
151147
writeStreams.stdout(chalk`{black.bgYellowBright WARN }${renderDuration(prettyDuration)} {blueBright ${namePad}} pre_script\n`);
152-
const outputLog = await fs.readFile(`${cwd}/${stateDir}/output/${safeName}.log`, "utf8");
148+
const outputLog = await fs.readFile(`${stateDir}/output/${safeName}.log`, "utf8");
153149
for (const line of outputLog.split(/\r?\n/).filter(j => !j.includes("[32m$ ")).filter(j => j !== "").slice(-3)) {
154150
writeStreams.stdout(chalk` {yellow >} ${line}\n`);
155151
}
@@ -170,7 +166,7 @@ export class Commander {
170166
const namePad = name.padEnd(jobNamePad);
171167
const safeName = Utils.safeDockerString(name);
172168
writeStreams.stdout(chalk`{black.bgRed FAIL }${renderDuration(prettyDuration)} {blueBright ${namePad}}\n`);
173-
const outputLog = await fs.readFile(`${cwd}/${stateDir}/output/${safeName}.log`, "utf8");
169+
const outputLog = await fs.readFile(`${stateDir}/output/${safeName}.log`, "utf8");
174170
for (const line of outputLog.split(/\r?\n/).filter(j => !j.includes("[32m$ ")).filter(j => j !== "").slice(-3)) {
175171
writeStreams.stdout(chalk` {red >} ${line}\n`);
176172
}

src/handler.ts

+11-25
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,24 @@ import {Utils} from "./utils.js";
1313
import {Argv} from "./argv.js";
1414
import assert from "assert";
1515

16-
const generateGitIgnore = (cwd: string, stateDir: string) => {
17-
const gitIgnoreFilePath = `${cwd}/${stateDir}/.gitignore`;
18-
const gitIgnoreContent = "*\n!.gitignore\n";
19-
if (!fs.existsSync(gitIgnoreFilePath)) {
20-
fs.outputFileSync(gitIgnoreFilePath, gitIgnoreContent);
21-
}
22-
};
23-
2416
export async function handler (args: any, writeStreams: WriteStreams, jobs: Job[] = []) {
2517
const argv = await Argv.build(args, writeStreams);
2618
const cwd = argv.cwd;
2719
const stateDir = argv.stateDir;
28-
const file = argv.file;
2920
let parser: Parser | null = null;
3021

3122
if (argv.completion) {
3223
yargs(process.argv.slice(2)).showCompletionScript();
3324
return [];
3425
}
3526

36-
assert(fs.existsSync(`${cwd}/${file}`), `${path.resolve(cwd)}/${file} could not be found`);
37-
3827
if (argv.fetchIncludes) {
3928
await Parser.create(argv, writeStreams, 0, jobs);
4029
return [];
4130
}
4231

4332
if (argv.preview) {
44-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
33+
const pipelineIid = await state.getPipelineIid(stateDir);
4534
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs, false);
4635
const gitlabData = parser.gitlabData;
4736
for (const jobName of Object.keys(gitlabData)) {
@@ -55,46 +44,43 @@ export async function handler (args: any, writeStreams: WriteStreams, jobs: Job[
5544
}
5645
writeStreams.stdout(`---\n${yaml.dump(gitlabData, {lineWidth: 160})}`);
5746
} else if (argv.list || argv.listAll) {
58-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
47+
const pipelineIid = await state.getPipelineIid(stateDir);
5948
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
6049
Commander.runList(parser, writeStreams, argv.listAll);
6150
} else if (argv.listJson) {
62-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
51+
const pipelineIid = await state.getPipelineIid(stateDir);
6352
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
6453
Commander.runJson(parser, writeStreams);
6554
} else if (argv.listCsv || argv.listCsvAll) {
66-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
55+
const pipelineIid = await state.getPipelineIid(stateDir);
6756
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
6857
Commander.runCsv(parser, writeStreams, argv.listCsvAll);
6958
} else if (argv.job.length > 0) {
7059
assert(argv.stage === null, "You cannot use --stage when starting individual jobs");
71-
generateGitIgnore(cwd, stateDir);
7260
const time = process.hrtime();
7361
if (argv.needs || argv.onlyNeeds) {
74-
await fs.remove(`${cwd}/${stateDir}/artifacts`);
75-
await state.incrementPipelineIid(cwd, stateDir);
62+
await fs.remove(`${stateDir}/artifacts`);
63+
await state.incrementPipelineIid(stateDir);
7664
}
77-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
65+
const pipelineIid = await state.getPipelineIid(stateDir);
7866
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
7967
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
8068
await Commander.runJobs(argv, parser, writeStreams);
8169
if (argv.needs || argv.onlyNeeds) {
8270
writeStreams.stderr(chalk`{grey pipeline finished} in {grey ${prettyHrtime(process.hrtime(time))}}\n`);
8371
}
8472
} else if (argv.stage) {
85-
generateGitIgnore(cwd, stateDir);
8673
const time = process.hrtime();
87-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
74+
const pipelineIid = await state.getPipelineIid(stateDir);
8875
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
8976
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
9077
await Commander.runJobsInStage(argv, parser, writeStreams);
9178
writeStreams.stderr(chalk`{grey pipeline finished} in {grey ${prettyHrtime(process.hrtime(time))}}\n`);
9279
} else {
93-
generateGitIgnore(cwd, stateDir);
9480
const time = process.hrtime();
95-
await fs.remove(`${cwd}/${stateDir}/artifacts`);
96-
await state.incrementPipelineIid(cwd, stateDir);
97-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
81+
await fs.remove(`${stateDir}/artifacts`);
82+
await state.incrementPipelineIid(stateDir);
83+
const pipelineIid = await state.getPipelineIid(stateDir);
9884
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
9985
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
10086
await Commander.runPipeline(argv, parser, writeStreams);

src/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ process.on("SIGUSR2", async () => await cleanupJobResources(jobs));
104104
})
105105
.option("cwd", {
106106
type: "string",
107-
description: "Path to a current working directory",
107+
description: "Path to the current working directory of the gitlab-ci-local executor",
108108
requiresArg: true,
109109
})
110110
.option("completion", {
@@ -144,17 +144,17 @@ process.on("SIGUSR2", async () => await cleanupJobResources(jobs));
144144
})
145145
.option("state-dir", {
146146
type: "string",
147-
description: "Location of the .gitlab-ci-local state dir, relative to cwd, eg. (symfony/.gitlab-ci-local/)",
147+
description: "Location of the .gitlab-ci-local state dir",
148148
requiresArg: false,
149149
})
150150
.option("file", {
151151
type: "string",
152-
description: "Location of the .gitlab-ci.yml, relative to cwd, eg. (gitlab/.gitlab-ci.yml)",
152+
description: "Location of the .gitlab-ci.yml",
153153
requiresArg: false,
154154
})
155155
.option("home", {
156156
type: "string",
157-
description: "Location of the HOME .gitlab-ci-local folder ($HOME/.gitlab-ci-local/variables.yml)",
157+
description: "Location of the HOME(gcl global config) [default: $HOME/.gitlab-ci-local]",
158158
requiresArg: false,
159159
})
160160
.option("shell-isolation", {
@@ -273,7 +273,7 @@ process.on("SIGUSR2", async () => await cleanupJobResources(jobs));
273273
completionFilter();
274274
} else {
275275
Argv.build({...yargsArgv, autoCompleting: true})
276-
.then(argv => state.getPipelineIid(argv.cwd, argv.stateDir).then(pipelineIid => ({argv, pipelineIid})))
276+
.then(argv => state.getPipelineIid(argv.stateDir).then(pipelineIid => ({argv, pipelineIid})))
277277
.then(({argv, pipelineIid}) => Parser.create(argv, new WriteStreamsMock(), pipelineIid, []))
278278
.then((parser) => {
279279
const jobNames = [...parser.jobs.values()].filter((j) => j.when != "never").map((j) => j.name);

0 commit comments

Comments
 (0)