feat: try multiple default config files

This commit is contained in:
2024-01-29 02:34:33 +02:00
committed by Chen Asraf
parent 9ce2845ace
commit 89aacb58fd
3 changed files with 105 additions and 22 deletions

View File

@@ -26,9 +26,7 @@ export default {
coverageDirectory: "coverage",
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
coveragePathIgnorePatterns: ["/node_modules/", "scaffold.config.js"],
// Indicates which provider should be used to instrument code for coverage
coverageProvider: "v8",

View File

@@ -1,5 +1,6 @@
import path from "node:path"
import os from "node:os"
import fs from "node:fs/promises"
import { log } from "./logger"
import { AsyncResolver, LogConfig, LogLevel, ScaffoldCmdConfig, ScaffoldConfigMap } from "./types"
import { spawn } from "node:child_process"
@@ -22,25 +23,7 @@ export async function getGitConfig(
clone.on("error", reject)
clone.on("close", async (code) => {
if (code === 0) {
log(logConfig, LogLevel.info, `Loading config from git repo: ${repoUrl}`)
// TODO search for dynamic config file in repo if not provided
const filename = file || "scaffold.config.js"
const absolutePath = path.resolve(tmpPath, filename)
const loadedConfig = await resolve(
async () => (await import(absolutePath)).default as ScaffoldConfigMap,
logConfig,
)
log(logConfig, LogLevel.info, `Loaded config from git`)
log(logConfig, LogLevel.debug, `Raw config:`, loadedConfig)
const fixedConfig: ScaffoldConfigMap = {}
for (const [k, v] of Object.entries(loadedConfig)) {
fixedConfig[k] = {
...v,
templates: v.templates.map((t) => path.resolve(tmpPath, t)),
}
}
res(wrapNoopResolver(fixedConfig))
res(await loadGitConfig({ logConfig, url: repoUrl, file, tmpPath }))
return
}
@@ -48,3 +31,52 @@ export async function getGitConfig(
})
})
}
/** @internal */
export async function loadGitConfig({
logConfig,
url: repoUrl,
file,
tmpPath,
}: {
logConfig: LogConfig
url: string
file: string
tmpPath: string
}): Promise<AsyncResolver<ScaffoldCmdConfig, ScaffoldConfigMap>> {
log(logConfig, LogLevel.info, `Loading config from git repo: ${repoUrl}`)
const filename = file || (await findConfigFile(tmpPath))
const absolutePath = path.resolve(tmpPath, filename)
const loadedConfig = await resolve(async () => (await import(absolutePath)).default as ScaffoldConfigMap, logConfig)
log(logConfig, LogLevel.info, `Loaded config from git`)
log(logConfig, LogLevel.debug, `Raw config:`, loadedConfig)
const fixedConfig: ScaffoldConfigMap = {}
for (const [k, v] of Object.entries(loadedConfig)) {
fixedConfig[k] = {
...v,
templates: v.templates.map((t) => path.resolve(tmpPath, t)),
}
}
await fs.rm(tmpPath, { recursive: true })
return wrapNoopResolver(fixedConfig)
}
/** @internal */
export async function findConfigFile(root: string): Promise<string> {
const allowed = ["mjs", "cjs", "js", "json"].reduce((acc, ext) => {
acc.push(`scaffold.config.${ext}`)
acc.push(`scaffold.${ext}`)
return acc
}, [] as string[])
for (const file of allowed) {
const exists = await fs
.stat(path.resolve(root, file))
.then(() => true)
.catch(() => false)
if (exists) {
return file
}
}
throw new Error(`Could not find config file in git repo`)
}

View File

@@ -1,8 +1,12 @@
import mockFs from "mock-fs"
import FileSystem from "mock-fs/lib/filesystem"
import { Console } from "console"
import { LogLevel, ScaffoldCmdConfig } from "../src/types"
import * as config from "../src/config"
import { resolve } from "../src/utils"
// @ts-ignore
import * as configFile from "../scaffold.config"
import { findConfigFile } from "../src/git"
jest.mock("../src/git", () => {
return {
@@ -28,6 +32,11 @@ const blankCliConf: ScaffoldCmdConfig = {
quiet: false,
}
const blankConfig: ScaffoldCmdConfig = {
...blankCliConf,
data: {},
}
describe("config", () => {
describe("parseAppendData", () => {
test('works for "key=value"', () => {
@@ -102,4 +111,48 @@ describe("config", () => {
expect(result).toEqual(configFile)
})
})
describe("findConfigFile", () => {
const struct1 = {
"scaffold.config.js": `module.exports = '${JSON.stringify(blankConfig)}'`,
}
const struct2 = {
"scaffold.js": `module.exports = '${JSON.stringify(blankConfig)}'`,
}
const struct3 = {
"scaffold.cjs": `module.exports = '${JSON.stringify(blankConfig)}'`,
}
const struct4 = {
"scaffold.json": JSON.stringify(blankConfig),
}
function withMock(fileStruct: FileSystem.DirectoryItems, testFn: jest.EmptyFunction): jest.EmptyFunction {
return () => {
beforeEach(() => {
// console.log("Mocking:", fileStruct)
console = new Console(process.stdout, process.stderr)
mockFs(fileStruct)
// logMock = jest.spyOn(console, 'log').mockImplementation((...args) => {
// logsTemp.push(args)
// })
})
testFn()
afterEach(() => {
// console.log("Restoring mock")
mockFs.restore()
})
}
}
for (const struct of [struct1, struct2, struct3, struct4]) {
const [k] = Object.keys(struct)
describe(`finds config file ${k}`, () => {
withMock(struct, async () => {
const result = await findConfigFile(process.cwd())
expect(result).toEqual(k)
})
})
}
})
})