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