parent
7421ff513d
commit
ae6996372b
@ -0,0 +1,85 @@ |
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { Command } from "commander"; |
||||||
|
// NOTE: this changed in node 18 to be node:url for...stupid
|
||||||
|
import { fileURLToPath } from "url"; |
||||||
|
import { glob } from "../lib/tooling.js"; |
||||||
|
import path from "path"; |
||||||
|
import assert from "assert"; |
||||||
|
import fs from "fs"; |
||||||
|
|
||||||
|
// BUG: this will load the commands but most of them assume the root
|
||||||
|
const __filename = fileURLToPath(import.meta.url); |
||||||
|
const { dir } = path.parse(__filename); |
||||||
|
let __dirname = path.resolve(dir); |
||||||
|
|
||||||
|
// now even exec commands will know where the project root is
|
||||||
|
process.env['PROJECT_ROOT'] = path.resolve(path.join(__dirname, "..")); |
||||||
|
|
||||||
|
const program = new Command(); |
||||||
|
// remember that glob doesn't like windows \
|
||||||
|
const command_dir = path.resolve(path.join(__dirname, "..", "commands")); |
||||||
|
|
||||||
|
if(!fs.existsSync(command_dir)) { |
||||||
|
console.error("ERROR: there is no command directory at", command_dir); |
||||||
|
process.exit(1); |
||||||
|
} |
||||||
|
|
||||||
|
program |
||||||
|
.name("bando") |
||||||
|
.description("Command runner for the bando project.") |
||||||
|
.version("0.1.0"); |
||||||
|
|
||||||
|
// only load the commands modules if any options are given
|
||||||
|
|
||||||
|
if(process.argv.length === 2) { |
||||||
|
console.log("COMMANDS:\n"); |
||||||
|
const commands = glob(`${command_dir}/*.js`).map(cmd => { |
||||||
|
console.log(path.parse(cmd).name); |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
if(process.platform === "win32") { |
||||||
|
console.log("\nUse './bando help' for full help."); |
||||||
|
} else { |
||||||
|
console.log("\nUse './bando.js help' for full help."); |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
try { |
||||||
|
const name = process.argv[2]; |
||||||
|
const command = path.join(command_dir, `${name}.js`); |
||||||
|
if(fs.existsSync(command)) { |
||||||
|
const mod = await import(`file://${command}`); |
||||||
|
|
||||||
|
assert(mod.description, `export const description missing in ${command}`); |
||||||
|
assert(mod.main, `export const main missing in ${command}`); |
||||||
|
|
||||||
|
const build = program.command(name) |
||||||
|
.description(mod.description) |
||||||
|
.action(mod.main); |
||||||
|
|
||||||
|
if(mod.options) { |
||||||
|
mod.options.forEach(opt => build.option(...opt)); |
||||||
|
} |
||||||
|
|
||||||
|
if(mod.required) { |
||||||
|
mod.required.forEach(opt => build.requiredOption(...opt)); |
||||||
|
} |
||||||
|
|
||||||
|
if(mod.argument) { |
||||||
|
build.argument(...mod.argument); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch(error) { |
||||||
|
console.log(error, `Loading file ${process.argv[2]}`); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
program.parse(); |
||||||
|
} catch(error) { |
||||||
|
console.log("------------- ERROR, here's the stack trace."); |
||||||
|
console.error(error.stack); |
||||||
|
process.exit(1); |
||||||
|
} |
@ -1,43 +0,0 @@ |
|||||||
import glob from "fast-glob"; |
|
||||||
import path from "path"; |
|
||||||
|
|
||||||
const test_files = await glob("./tests/**/*_test?.js"); |
|
||||||
|
|
||||||
const stats = { |
|
||||||
pass: 0, fail: 0 |
|
||||||
} |
|
||||||
|
|
||||||
const errors = {} |
|
||||||
|
|
||||||
const report_error = (id, error) => { |
|
||||||
console.error(error, `Running function ${id}`); |
|
||||||
} |
|
||||||
|
|
||||||
for(let suite_name of test_files) { |
|
||||||
const full_path = path.resolve(suite_name); |
|
||||||
const test_module = await import(`file://${full_path}`); |
|
||||||
|
|
||||||
for(let [name, func] of Object.entries(test_module)) { |
|
||||||
const id = `${suite_name}:${name}`; |
|
||||||
console.log("------- RUNNING", id); |
|
||||||
try { |
|
||||||
await func(); |
|
||||||
stats.pass += 1; |
|
||||||
} catch(error) { |
|
||||||
stats.fail += 1; |
|
||||||
errors[id] = error; |
|
||||||
report_error(func, id, error); |
|
||||||
} |
|
||||||
|
|
||||||
console.log("\n"); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if(Object.keys(errors).length > 0) { |
|
||||||
console.log("!!!!!!!!!!!!!! ERRORS !!!!!!!!!!!!!!!!"); |
|
||||||
for(let [id, error] of Object.entries(errors)) { |
|
||||||
report_error(id, error); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
console.log("\nPASS: ", stats.pass, "FAIL: ", stats.fail); |
|
@ -0,0 +1,53 @@ |
|||||||
|
import glob from "fast-glob"; |
||||||
|
import path from "path"; |
||||||
|
|
||||||
|
export const description = "Runs tests."; |
||||||
|
|
||||||
|
export const options = []; |
||||||
|
|
||||||
|
export const required = [ |
||||||
|
["--glob <regex>", "Directory pattern to find test runners.", "./tests/**/*_test?.js"], |
||||||
|
]; |
||||||
|
|
||||||
|
const report_error = (id, error) => { |
||||||
|
console.error(error, `Running function ${id}`); |
||||||
|
} |
||||||
|
|
||||||
|
export const main = async (opts) => { |
||||||
|
const test_files = await glob(opts.glob); |
||||||
|
|
||||||
|
const stats = { |
||||||
|
pass: 0, fail: 0 |
||||||
|
} |
||||||
|
|
||||||
|
const errors = {} |
||||||
|
|
||||||
|
for(let suite_name of test_files) { |
||||||
|
const full_path = path.resolve(suite_name); |
||||||
|
const test_module = await import(`file://${full_path}`); |
||||||
|
|
||||||
|
for(let [name, func] of Object.entries(test_module)) { |
||||||
|
const id = `${suite_name}:${name}`; |
||||||
|
console.log("------- RUNNING", id); |
||||||
|
try { |
||||||
|
await func(); |
||||||
|
stats.pass += 1; |
||||||
|
} catch(error) { |
||||||
|
stats.fail += 1; |
||||||
|
errors[id] = error; |
||||||
|
report_error(func, id, error); |
||||||
|
} |
||||||
|
|
||||||
|
console.log("\n"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if(Object.keys(errors).length > 0) { |
||||||
|
console.log("!!!!!!!!!!!!!! ERRORS !!!!!!!!!!!!!!!!"); |
||||||
|
for(let [id, error] of Object.entries(errors)) { |
||||||
|
report_error(id, error); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
console.log("\nPASS: ", stats.pass, "FAIL: ", stats.fail); |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
import fg from "fast-glob"; |
||||||
|
|
||||||
|
/* |
||||||
|
Fixes some common problems with `fast-glob` on windows. It removes |
||||||
|
leading "C:\" from paths and replaces all of the `\\` with `/`. |
||||||
|
|
||||||
|
__BUG__: This obviously won't work if you're on a different drive than C:. |
||||||
|
|
||||||
|
+ `path string` -- The path/glob pattern to use. |
||||||
|
*/ |
||||||
|
export const glob = (path) => { |
||||||
|
if(process.platform === "win32") { |
||||||
|
// fast-glob doesn't understand \\ or C:\
|
||||||
|
const fixed_path = path.replace("C:","").replaceAll('\\', '/') |
||||||
|
|
||||||
|
return fg.sync(fixed_path); |
||||||
|
} else { |
||||||
|
return fg.sync(path); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue