fix(config): fn config load

closes #63
This commit is contained in:
2023-11-28 00:12:39 +02:00
parent 0fa1ad4db7
commit 457c90470b
10 changed files with 119 additions and 79 deletions

View File

@@ -8,14 +8,22 @@ jobs:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip docs]')"
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- name: Checkout
uses: actions/checkout@v3
with:
run_install: |
- recursive: true
args: [--frozen-lockfile, --strict-peer-dependencies]
- run: pnpm build-docs
- uses: peaceiris/actions-gh-pages@v3
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18.x"
- name: Install PNPM
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build Docs
run: pnpm build-docs
- name: Deploy on GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs

View File

@@ -8,11 +8,19 @@ jobs:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- name: Checkout
uses: actions/checkout@v3
with:
run_install: |
- recursive: true
args: [--frozen-lockfile, --strict-peer-dependencies]
- run: pnpm build
- run: pnpm test
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18.x"
- name: Install PNPM
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Tests
run: pnpm test
- name: Build Package
run: pnpm build

View File

@@ -2,11 +2,18 @@ name: Test & Build
on:
push:
branches: [ master, develop, pre, feat/*, fix/* ]
branches: [master, develop, pre, feat/*, fix/*]
permissions:
contents: read # for checkout
jobs:
test:
name: Test
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
@@ -15,22 +22,36 @@ jobs:
- recursive: true
args: [--frozen-lockfile, --strict-peer-dependencies]
- run: pnpm test
if: "!contains(github.event.head_commit.message, '[skip test]')"
build:
name: Build
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[skip ci]')"
needs: test
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- name: Checkout
uses: actions/checkout@v3
with:
run_install: |
- recursive: true
args: [--frozen-lockfile, --strict-peer-dependencies]
- run: pnpm build
- run: cd ./dist && pnpm pack --pack-destination=../
- run: pnpm semantic-release
if: "!contains(github.event.head_commit.message, '[skip publish]')"
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "18.x"
- name: Install PNPM
run: npm i -g pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run Tests
run: pnpm test
- name: Build Package
run: pnpm build
- name: Pack
run: cd ./dist && pnpm pack --pack-destination=../
- name: Semantic Release
run: npx semantic-release
env:
NPM_TOKEN: "${{ secrets.NPM_TOKEN }}"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -39,11 +39,12 @@
"date-fns": "^2.30.0",
"glob": "^10.3.3",
"handlebars": "^4.7.7",
"massarg": "^1.0.7-pre.1"
"massarg": "1.0.7-pre.1"
},
"devDependencies": {
"@knodes/typedoc-plugin-pages": "^0.23.4",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/exec": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@semantic-release/release-notes-generator": "^10.0.3",
"@types/jest": "^29.5.1",

View File

@@ -1,13 +1,16 @@
/** @type {import('simple-scaffold').ScaffoldConfigFile} */
module.exports = {
default: {
templates: ["examples/test-input/Component"],
output: "examples/test-output",
data: { property: "myProp", value: "10" },
},
component: {
templates: ["examples/test-input/Component"],
output: "examples/test-output/component",
data: { property: "myProp", value: "10" },
},
module.exports = (conf) => {
console.log("Config:", conf)
return {
default: {
templates: ["examples/test-input/Component"],
output: "examples/test-output",
data: { property: "myProp", value: "10" },
},
component: {
templates: ["examples/test-input/Component"],
output: "examples/test-output/component",
data: { property: "myProp", value: "10" },
},
}
}

View File

@@ -5,7 +5,7 @@ import { LogLevel, ScaffoldCmdConfig } from "./types"
import { Scaffold } from "./scaffold"
import path from "node:path"
import fs from "node:fs/promises"
import { parseAppendData, parseConfig } from "./config"
import { parseAppendData, parseConfigFile } from "./config"
export async function parseCliArgs(args = process.argv.slice(2)) {
const pkgFile = await fs.readFile(path.join(__dirname, "package.json"))
@@ -16,7 +16,7 @@ export async function parseCliArgs(args = process.argv.slice(2)) {
return (
massarg<ScaffoldCmdConfig>()
.main(async (config) => {
const _config = await parseConfig(config)
const _config = await parseConfigFile(config)
return Scaffold(_config)
})
.option({

View File

@@ -8,7 +8,6 @@ import {
ScaffoldConfig,
ScaffoldConfigFile,
} from "./types"
import { OptionsBase } from "massarg/types"
import { handlebarsParse } from "./parser"
import { log } from "./logger"
import { resolve, wrapNoopResolver } from "./utils"
@@ -30,7 +29,7 @@ export function getOptionValueForFile<T>(
)
}
export function parseAppendData(value: string, options: ScaffoldCmdConfig & OptionsBase): unknown {
export function parseAppendData(value: string, options: ScaffoldCmdConfig): unknown {
const data = options.data ?? {}
const [key, val] = value.split(/\:?=/)
// raw
@@ -45,7 +44,7 @@ function isWrappedWithQuotes(string: string): boolean {
}
/** @internal */
export async function parseConfig(config: ScaffoldCmdConfig & OptionsBase): Promise<ScaffoldConfig> {
export async function parseConfigFile(config: ScaffoldCmdConfig): Promise<ScaffoldConfig> {
let c: ScaffoldConfig = config
if (config.github) {
log(config, LogLevel.Info, `Loading config from github ${config.github}`)
@@ -61,16 +60,19 @@ export async function parseConfig(config: ScaffoldCmdConfig & OptionsBase): Prom
quiet: config.quiet,
verbose: config.verbose,
})
const configImport = await resolve(configPromise, config)
let configImport = await resolve(configPromise, config)
if (typeof configImport.default === "function" || configImport.default instanceof Promise) {
configImport = await resolve(configImport.default, config)
}
if (!configImport[key]) {
throw new Error(`Template "${key}" not found in ${configFile}`)
}
const importedKey = configImport[key]
c = {
...config,
...configImport[key],
...importedKey,
data: {
...configImport[key].data,
...(importedKey as any).data,
...config.data,
},
}

View File

@@ -1,9 +1,9 @@
import path from "node:path"
import os from "node:os"
import { log } from "./logger"
import { AsyncResolver, LogConfig, LogLevel, ScaffoldCmdConfig, ScaffoldConfigMap } from "./types"
import { AsyncResolver, LogConfig, LogLevel, ScaffoldCmdConfig, ScaffoldConfig, ScaffoldConfigMap } from "./types"
import { spawn } from "node:child_process"
import { wrapNoopResolver } from "./utils"
import { resolve, wrapNoopResolver } from "./utils"
export async function getGitConfig(
url: URL,
@@ -15,7 +15,7 @@ export async function getGitConfig(
const tmpPath = path.resolve(os.tmpdir(), `scaffold-config-${Date.now()}`)
return new Promise((resolve, reject) => {
return new Promise((res, reject) => {
const clone = spawn("git", ["clone", "--depth", "1", repoUrl, tmpPath])
clone.on("error", reject)
@@ -24,18 +24,21 @@ export async function getGitConfig(
log(logConfig, LogLevel.Info, `Loading config from git repo: ${repoUrl}`)
const hashPath = url.hash?.replace("#", "") || "scaffold.config.js"
const absolutePath = path.resolve(tmpPath, hashPath)
const loadedConfig = (await import(absolutePath)).default as ScaffoldConfigMap
log(logConfig, LogLevel.Info, `Loaded config from git`)
log(logConfig, LogLevel.Debug, `Raw config:`, loadedConfig)
const fixedConfig: ScaffoldConfigMap = Object.fromEntries(
Object.entries(loadedConfig).map(([k, v]) => [
k,
// use absolute paths for template as config is necessarily in another directory
{ ...v, templates: v.templates.map((t) => path.resolve(tmpPath, t)) },
]),
const loadedConfig = await resolve(
async () => (await import(absolutePath)).default as ScaffoldConfigMap,
logConfig,
)
resolve(wrapNoopResolver(fixedConfig))
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))
return
}

View File

@@ -16,10 +16,9 @@ import {
handleTemplateFile,
} from "./file"
import { LogLevel, MinimalConfig, Resolver, ScaffoldCmdConfig, ScaffoldConfig } from "./types"
import { OptionsBase } from "massarg/types"
import { defaultHelpers, registerHelpers } from "./parser"
import { log, logInitStep, logInputFile } from "./logger"
import { parseConfig } from "./config"
import { parseConfigFile } from "./config"
/**
* Create a scaffold using given `options`.
@@ -110,7 +109,7 @@ export async function Scaffold(config: ScaffoldConfig): Promise<void> {
* @category Main
* @return {Promise<void>} A promise that resolves when the scaffold is complete
*/
Scaffold.fromConfig = async function (
Scaffold.fromConfig = async function(
/** The path or URL to the config file */
pathOrUrl: string,
/** Information needed before loading the config */
@@ -118,7 +117,7 @@ Scaffold.fromConfig = async function (
/** Any overrides to the loaded config */
overrides?: Resolver<ScaffoldCmdConfig, Partial<Omit<ScaffoldConfig, "name">>>,
): Promise<void> {
const _cmdConfig: ScaffoldCmdConfig & OptionsBase = {
const _cmdConfig: ScaffoldCmdConfig = {
dryRun: false,
output: process.cwd(),
verbose: LogLevel.Info,
@@ -126,13 +125,11 @@ Scaffold.fromConfig = async function (
templates: [],
createSubFolder: false,
quiet: false,
help: false,
extras: [],
config: pathOrUrl,
...config,
}
const _overrides = resolve(overrides, _cmdConfig)
const _config = await parseConfig(_cmdConfig)
const _config = await parseConfigFile(_cmdConfig)
return Scaffold({ ..._config, ..._overrides })
}

View File

@@ -1,5 +1,4 @@
import { ScaffoldCmdConfig } from "../src/types"
import { OptionsBase } from "massarg/types"
import * as config from "../src/config"
import { resolve } from "../src/utils"
// @ts-ignore
@@ -10,14 +9,14 @@ jest.mock("../src/git", () => {
__esModule: true,
...jest.requireActual("../src/git"),
getGitConfig: () => {
return Promise.resolve({ default: blankCliConf })
return Promise.resolve(blankCliConf)
},
}
})
const { githubPartToUrl, parseAppendData, parseConfig, parseConfigSelection } = config
const { githubPartToUrl, parseAppendData, parseConfigFile, parseConfigSelection } = config
const blankCliConf: ScaffoldCmdConfig & OptionsBase = {
const blankCliConf: ScaffoldCmdConfig = {
verbose: 0,
name: "",
output: "",
@@ -27,8 +26,6 @@ const blankCliConf: ScaffoldCmdConfig & OptionsBase = {
createSubFolder: false,
dryRun: false,
quiet: false,
extras: [],
help: false,
}
describe("config", () => {
@@ -99,24 +96,24 @@ describe("config", () => {
})
})
describe("parseConfig", () => {
describe("parseConfigFile", () => {
test("normal config does not change", async () => {
expect(
await parseConfig({
await parseConfigFile({
...blankCliConf,
}),
).toEqual(blankCliConf)
})
describe("appendData", () => {
test("appends", async () => {
const result = await parseConfig({
const result = await parseConfigFile({
...blankCliConf,
appendData: { key: "value" },
})
expect(result?.data?.key).toEqual("value")
})
test("overwrites existing value", async () => {
const result = await parseConfig({
const result = await parseConfigFile({
...blankCliConf,
data: { num: "123" },
appendData: { num: "1234" },
@@ -135,7 +132,7 @@ describe("config", () => {
verbose: 0,
})
const result = await resolve(resultFn, blankCliConf)
expect(result).toEqual({ default: blankCliConf })
expect(result).toEqual(blankCliConf)
})
test("gets local file config", async () => {