Skip to content

Commit 8bca3be

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

17 files changed

+179
-102
lines changed

Diff for: 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[] {

Diff for: 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
}

Diff for: src/handler.ts

+11-26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as yaml from "js-yaml";
22
import chalk from "chalk";
3-
import path from "path";
43
import fs from "fs-extra";
54
import yargs from "yargs";
65
import {Commander} from "./commander.js";
@@ -13,35 +12,24 @@ import {Utils} from "./utils.js";
1312
import {Argv} from "./argv.js";
1413
import assert from "assert";
1514

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-
2415
export async function handler (args: any, writeStreams: WriteStreams, jobs: Job[] = []) {
2516
const argv = await Argv.build(args, writeStreams);
2617
const cwd = argv.cwd;
2718
const stateDir = argv.stateDir;
28-
const file = argv.file;
2919
let parser: Parser | null = null;
3020

3121
if (argv.completion) {
3222
yargs(process.argv.slice(2)).showCompletionScript();
3323
return [];
3424
}
3525

36-
assert(fs.existsSync(`${cwd}/${file}`), `${path.resolve(cwd)}/${file} could not be found`);
37-
3826
if (argv.fetchIncludes) {
3927
await Parser.create(argv, writeStreams, 0, jobs);
4028
return [];
4129
}
4230

4331
if (argv.preview) {
44-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
32+
const pipelineIid = await state.getPipelineIid(stateDir);
4533
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs, false);
4634
const gitlabData = parser.gitlabData;
4735
for (const jobName of Object.keys(gitlabData)) {
@@ -55,46 +43,43 @@ export async function handler (args: any, writeStreams: WriteStreams, jobs: Job[
5543
}
5644
writeStreams.stdout(`---\n${yaml.dump(gitlabData, {lineWidth: 160})}`);
5745
} else if (argv.list || argv.listAll) {
58-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
46+
const pipelineIid = await state.getPipelineIid(stateDir);
5947
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
6048
Commander.runList(parser, writeStreams, argv.listAll);
6149
} else if (argv.listJson) {
62-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
50+
const pipelineIid = await state.getPipelineIid(stateDir);
6351
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
6452
Commander.runJson(parser, writeStreams);
6553
} else if (argv.listCsv || argv.listCsvAll) {
66-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
54+
const pipelineIid = await state.getPipelineIid(stateDir);
6755
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
6856
Commander.runCsv(parser, writeStreams, argv.listCsvAll);
6957
} else if (argv.job.length > 0) {
7058
assert(argv.stage === null, "You cannot use --stage when starting individual jobs");
71-
generateGitIgnore(cwd, stateDir);
7259
const time = process.hrtime();
7360
if (argv.needs || argv.onlyNeeds) {
74-
await fs.remove(`${cwd}/${stateDir}/artifacts`);
75-
await state.incrementPipelineIid(cwd, stateDir);
61+
await fs.remove(`${stateDir}/artifacts`);
62+
await state.incrementPipelineIid(stateDir);
7663
}
77-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
64+
const pipelineIid = await state.getPipelineIid(stateDir);
7865
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
7966
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
8067
await Commander.runJobs(argv, parser, writeStreams);
8168
if (argv.needs || argv.onlyNeeds) {
8269
writeStreams.stderr(chalk`{grey pipeline finished} in {grey ${prettyHrtime(process.hrtime(time))}}\n`);
8370
}
8471
} else if (argv.stage) {
85-
generateGitIgnore(cwd, stateDir);
8672
const time = process.hrtime();
87-
const pipelineIid = await state.getPipelineIid(cwd, stateDir);
73+
const pipelineIid = await state.getPipelineIid(stateDir);
8874
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
8975
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
9076
await Commander.runJobsInStage(argv, parser, writeStreams);
9177
writeStreams.stderr(chalk`{grey pipeline finished} in {grey ${prettyHrtime(process.hrtime(time))}}\n`);
9278
} else {
93-
generateGitIgnore(cwd, stateDir);
9479
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);
80+
await fs.remove(`${stateDir}/artifacts`);
81+
await state.incrementPipelineIid(stateDir);
82+
const pipelineIid = await state.getPipelineIid(stateDir);
9883
parser = await Parser.create(argv, writeStreams, pipelineIid, jobs);
9984
await Utils.rsyncTrackedFiles(cwd, stateDir, ".docker");
10085
await Commander.runPipeline(argv, parser, writeStreams);

Diff for: 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)