Skip to content

Commit

Permalink
Discover .fauna-project in parent directories (#248)
Browse files Browse the repository at this point in the history
* Add function to find the local config

* Add tests

* Simplify search to be unbounded
  • Loading branch information
macmv authored Sep 25, 2023
1 parent 938f436 commit 046f566
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 10 deletions.
47 changes: 38 additions & 9 deletions src/lib/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,10 @@ export class ShellConfig {
endpoint: Endpoint;

static read(flags: any, scope: string, role: string) {
const rootConfig = ini.parse(readFileOpt(getRootConfigFile()));
const rootConfig = ini.parse(readFileOpt(getRootConfigPath()));
const projectConfigPath = getProjectConfigPath();
const projectConfig = projectConfigPath
? ini.parse(fs.readFileSync(projectConfigPath, "utf8"))
? ini.parse(readFile(projectConfigPath))
: undefined;

return new ShellConfig({
Expand Down Expand Up @@ -279,16 +279,45 @@ const readFileOpt = (fileName: string) => {
}
};

const getRootConfigFile = () => {
const readFile = (fileName: string) => {
return fs.readFileSync(fileName, "utf8");
};

const getRootConfigPath = () => {
return path.join(os.homedir(), ".fauna-shell");
};

// TODO: Search upwards for a `.fauna-project` file
const getProjectConfigPath = () => {
const projectConfigPath = path.join(process.cwd(), ".fauna-project");
if (fs.existsSync(projectConfigPath)) {
return projectConfigPath;
} else {
export const getProjectConfigPath = (): string | undefined => {
let current;
try {
current = process.cwd();
} catch (err) {
// If the cwd is not accessible, just give up. If this happens, one of our
// dependencies actually explodes elsewhere, but we might as well handle
// errors where possible.
return undefined;
}

while (true) {
const projPath = path.join(current, ".fauna-project");
let stat;
stat = fs.statSync(projPath, {
// returns undefined instead of throwing if the file doesn't exist
throwIfNoEntry: false,
});
if (stat !== undefined && stat.isFile()) {
return projPath;
}

const currPath = path.parse(current);
// break if at root
if (currPath.base === "") {
break;
}
current = currPath.dir;
}

// if we got here, it means that there was no `.fauna-project` file, so we
// give up.
return undefined;
};
85 changes: 84 additions & 1 deletion test/lib/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import fs from "fs";
import { expect } from "chai";
import { ShellConfig, ShellOpts } from "../../src/lib/config";
import {
ShellConfig,
ShellOpts,
getProjectConfigPath,
} from "../../src/lib/config";
import sinon from "sinon";

const lookupEndpoint = (opts: ShellOpts) => {
return new ShellConfig(opts).lookupEndpoint();
Expand Down Expand Up @@ -312,3 +318,80 @@ describe("local config with flags", () => {
});
});
});

describe("getProjectConfigPath", () => {
it("searches cwd for a config", () => {
sinon.replace(process, "cwd", sinon.fake.returns("/foo/bar/baz"));

const stat = sinon.stub(fs, "statSync");
stat
.withArgs("/foo/bar/baz/.fauna-project", { throwIfNoEntry: false })
.returns({
isFile: () => true,
} as any);

expect(getProjectConfigPath()).to.equal("/foo/bar/baz/.fauna-project");
expect(stat.callCount).to.equal(1);

sinon.restore();
});

it("searches upwards for a config", () => {
sinon.replace(process, "cwd", sinon.fake.returns("/foo/bar/baz"));

const stat = sinon.stub(fs, "statSync");
stat
.withArgs("/foo/bar/baz/.fauna-project", { throwIfNoEntry: false })
.returns(undefined)
.withArgs("/foo/bar/.fauna-project", { throwIfNoEntry: false })
.returns({
isFile: () => true,
} as any);

expect(getProjectConfigPath()).to.equal("/foo/bar/.fauna-project");
expect(stat.callCount).to.equal(2);

sinon.restore();
});

it("stops searching after finding the root", () => {
sinon.replace(process, "cwd", sinon.fake.returns("/foo/bar/baz"));

const stat = sinon.stub(fs, "statSync");
stat
.withArgs("/foo/bar/baz/.fauna-project", { throwIfNoEntry: false })
.returns(undefined)
.withArgs("/foo/bar/.fauna-project", { throwIfNoEntry: false })
.returns(undefined)
.withArgs("/foo/.fauna-project", { throwIfNoEntry: false })
.returns(undefined)
.withArgs("/.fauna-project", { throwIfNoEntry: false })
.returns(undefined);

expect(getProjectConfigPath()).to.equal(undefined);
expect(stat.callCount).to.equal(4);

sinon.restore();
});

it("fails silently if the CWD couldn't be found", () => {
sinon.replace(process, "cwd", sinon.fake.throws(new Error("No CWD")));

expect(getProjectConfigPath()).to.equal(undefined);

sinon.restore();
});

it("explodes if `stat` fails", () => {
sinon.replace(process, "cwd", sinon.fake.returns("/foo/bar/baz"));

const stat = sinon.stub(fs, "statSync");
stat
.withArgs("/foo/bar/baz/.fauna-project", { throwIfNoEntry: false })
.throws(new Error("Couldn't stat"));

expect(() => getProjectConfigPath()).to.throw("Couldn't stat");

sinon.restore();
});
});

0 comments on commit 046f566

Please sign in to comment.