Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support absolute path for options that makes sense #1360

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.pathExistsSync(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.pathExistsSync(`${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 fs from "fs-extra";
import yargs from "yargs";
import {Commander} from "./commander.js";
Expand All @@ -13,35 +12,24 @@ import {Utils} from "./utils.js";
import {Argv} from "./argv.js";
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(process.argv.slice(2)).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 @@ -104,7 +104,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 @@ -144,17 +144,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 @@ -273,7 +273,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