diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3ff4536 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: {} + +jobs: + lint: + uses: ./.github/workflows/node.yml + with: + run: npm run lint + test: + uses: ./.github/workflows/node.yml + with: + run: npm run -- test -p 360000 + build: + uses: ./.github/workflows/node.yml + with: + run: npm run build diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 0000000..b4bab90 --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,12 @@ +name: End-to-end tests + +on: + schedule: + - cron: '20 4 * * *' + workflow_dispatch: {} + +jobs: + e2e: + uses: ./.github/workflows/node.yml + with: + run: npm run -- test -t 360000 -p e2e diff --git a/.github/workflows/verify.yml b/.github/workflows/node.yml similarity index 53% rename from .github/workflows/verify.yml rename to .github/workflows/node.yml index 15bb7e1..0da2542 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/node.yml @@ -1,14 +1,14 @@ -name: CI +name: Continuous Integration on: - push: - branches: [master] - pull_request: - branches: [master] - workflow_dispatch: {} + workflow_call: + inputs: + run: + required: true + type: string jobs: - verify: + node: runs-on: ubuntu-latest strategy: matrix: @@ -20,7 +20,8 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: 'npm' - - run: npm ${{ vars.NPM_CI_FLAGS }} ci - - run: npm run lint - - run: npm run test - - run: npm run build + - run: npm config set registry ${{ vars.NPM_CI_REGISTRY }} + if: ${{ vars.NPM_CI_REGISTRY }} + - run: | + npm ci + ${{ inputs.run }} diff --git a/build/publish.js b/build/publish.js index 159daf1..76cdcce 100644 --- a/build/publish.js +++ b/build/publish.js @@ -2,12 +2,14 @@ const {Buffer} = require('buffer'); const {exec} = require('child_process'); const {createHash} = require('crypto'); const {createReadStream} = require('fs'); -const {cp, mkdir, writeFile} = require('fs/promises'); +const {cp, mkdir} = require('fs/promises'); const {join} = require('path'); const { processCode, + run, spawnWith, + writeFile, } = require('@flecks/core/src/server'); const Arborist = require('@npmcli/arborist'); const {glob} = require('glob'); @@ -25,18 +27,6 @@ const localVersions = {}; const packCache = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'publish'); const {workspaces} = require(join(FLECKS_CORE_ROOT, 'package.json')); -const run = (cmd) => ( - new Promise((resolve) => { - exec(cmd, (error, stdout) => { - if (error) { - resolve(undefined) - return; - } - resolve(stdout.trim()); - }); - }) -); - // Get integrity sums for creator dependencies. const packPkg = async (pkg) => { await processCode(spawnWith( diff --git a/package-lock.json b/package-lock.json index 4e1c6db..dd8663f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16237,7 +16237,7 @@ }, "packages/build": { "name": "@flecks/build", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { "@babel/core": "^7.12.10", @@ -16248,7 +16248,7 @@ "@babel/preset-env": "^7.12.11", "@babel/traverse": "^7.17.0", "@babel/types": "^7.17.0", - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "babel-loader": "^9.1.3", "babel-merge": "^3.0.0", "chai": "4.2.0", @@ -16305,7 +16305,7 @@ }, "packages/core": { "name": "@flecks/core", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { "debug": "4.3.1", @@ -16360,10 +16360,10 @@ }, "packages/create-app": { "name": "@flecks/create-app", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "commander": "11.1.0", "validate-npm-package-name": "^3.0.0" }, @@ -16371,8 +16371,8 @@ "create-app": "build/cli.js" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/create-app/node_modules/builtins": { @@ -16390,45 +16390,45 @@ }, "packages/create-fleck": { "name": "@flecks/create-fleck", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "commander": "11.1.0" }, "bin": { "create-fleck": "build/cli.js" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/db": { "name": "@flecks/db", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "sequelize": "^6.3.5", "sqlite3": "^5.0.2" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/docker": { "name": "@flecks/docker", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "debug": "^4.3.3" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/docker/node_modules/debug": { @@ -16449,47 +16449,47 @@ }, "packages/dox": { "name": "@flecks/dox", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { "@babel/core": "^7.17.2", "@babel/traverse": "^7.17.0", "@babel/types": "^7.17.0", - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "comment-parser": "^1.3.0", "rimraf": "^5.0.5" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/electron": { "name": "@flecks/electron", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "electron": "^28.1.4", "electron-devtools-installer": "^3.2.0" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/fleck": { "name": "@flecks/fleck", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "babel-merge": "^3.0.0", "debug": "^4.3.3", "mocha": "^10.2.0" }, "devDependencies": { - "@flecks/build": "^4.0.2", + "@flecks/build": "^4.0.5", "chai": "4.2.0" } }, @@ -16511,75 +16511,75 @@ }, "packages/passport": { "name": "@flecks/passport", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", - "@flecks/db": "^4.0.2", - "@flecks/redux": "^4.0.2", - "@flecks/session": "^4.0.2", + "@flecks/core": "^4.0.5", + "@flecks/db": "^4.0.5", + "@flecks/redux": "^4.0.5", + "@flecks/session": "^4.0.5", "passport": "^0.7.0" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/passport-local": { "name": "@flecks/passport-local", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", - "@flecks/passport": "^4.0.2", + "@flecks/core": "^4.0.5", + "@flecks/passport": "^4.0.5", "bcrypt": "^5.1.1", "passport-local": "^1.0.0" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/passport-local-react": { "name": "@flecks/passport-local-react", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", - "@flecks/passport-local": "^4.0.2", - "@flecks/passport-react": "^4.0.2", - "@flecks/react": "^4.0.2" + "@flecks/core": "^4.0.5", + "@flecks/passport-local": "^4.0.5", + "@flecks/passport-react": "^4.0.5", + "@flecks/react": "^4.0.5" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/passport-react": { "name": "@flecks/passport-react", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", - "@flecks/passport": "^4.0.2", - "@flecks/react": "^4.0.2", - "@flecks/react-redux": "^4.0.2", - "@flecks/web": "^4.0.2" + "@flecks/core": "^4.0.5", + "@flecks/passport": "^4.0.5", + "@flecks/react": "^4.0.5", + "@flecks/react-redux": "^4.0.5", + "@flecks/web": "^4.0.5" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/react": { "name": "@flecks/react", - "version": "4.0.2", + "version": "4.0.5", "hasInstallScript": true, "license": "MIT", "dependencies": { "@babel/preset-react": "^7.23.3", - "@flecks/core": "^4.0.2", - "@flecks/web": "^4.0.2", + "@flecks/core": "^4.0.5", + "@flecks/web": "^4.0.5", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", "babel-merge": "^3.0.0", "classnames": "^2.3.1", @@ -16595,55 +16595,55 @@ "redux-first-history": "5.1.1" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/react-redux": { "name": "@flecks/react-redux", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", - "@flecks/react": "^4.0.2", - "@flecks/redux": "^4.0.2", + "@flecks/core": "^4.0.5", + "@flecks/react": "^4.0.5", + "@flecks/redux": "^4.0.5", "react-redux": "^7.2.2" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/redis": { "name": "@flecks/redis", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "@socket.io/redis-adapter": "7.1.0", "connect-redis": "^5.0.0", "express-session": "^1.17.1", "redis": "4.0.3" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/redux": { "name": "@flecks/redux", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "@reduxjs/toolkit": "^1.5.0", "debug": "^4.3.3", "lodash.throttle": "^4.1.1", "reduce-reducers": "^1.0.4" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/redux/node_modules/debug": { @@ -16664,51 +16664,51 @@ }, "packages/repl": { "name": "@flecks/repl", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "command-exists": "^1.2.9", "debug": "4.3.1" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/server": { "name": "@flecks/server", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2" + "@flecks/core": "^4.0.5" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/session": { "name": "@flecks/session", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "express": "^4.18.2", "express-session": "^1.17.3" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/socket": { "name": "@flecks/socket", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { - "@flecks/core": "^4.0.2", - "@flecks/react": "^4.0.2", + "@flecks/core": "^4.0.5", + "@flecks/react": "^4.0.5", "msgpack-lite": "^0.1.26", "proxy-addr": "^2.0.6", "schemapack": "^1.4.2", @@ -16716,18 +16716,18 @@ "socket.io-client": "^4.1.2" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } }, "packages/web": { "name": "@flecks/web", - "version": "4.0.2", + "version": "4.0.5", "license": "MIT", "dependencies": { "@babel/parser": "^7.17.0", "@babel/types": "^7.17.0", - "@flecks/core": "^4.0.2", + "@flecks/core": "^4.0.5", "@webpack-cli/serve": "^2.0.5", "add-asset-html-webpack-plugin": "^6.0.0", "assert": "^2.1.0", @@ -16759,8 +16759,8 @@ "webpack-dev-server": "^4.15.1" }, "devDependencies": { - "@flecks/build": "^4.0.2", - "@flecks/fleck": "^4.0.2" + "@flecks/build": "^4.0.5", + "@flecks/fleck": "^4.0.5" } } } diff --git a/package.json b/package.json index 7f90a77..a77a02a 100644 --- a/package.json +++ b/package.json @@ -8,14 +8,14 @@ }, "scripts": { "build": "node build/tasks npm run build", - "ci": "act -j verify", "dox:bump": "npm run dox:gh-pages && cd dox && git add . && git commit -m $(git -C .. rev-parse HEAD) && git push origin gh-pages", "dox:gh-pages": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus build --out-dir ../dox-tmp && cd .. && rm -rf dox/* && mv dox-tmp/* dox && rmdir dox-tmp", "dox:serve": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus build --no-minify --out-dir ../dox-tmp && node_modules/.bin/docusaurus serve --dir ../dox-tmp", "dox": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus", "lint": "node build/tasks npm run lint", "publish": "node build/publish --provenance", - "test": "node build/tasks npm run -- test -t 300000" + "test": "node build/tasks npm run -- test", + "verify": "act workflow_dispatch" }, "workspaces": [ "packages/*" diff --git a/packages/build/build/build.eslint.config.js b/packages/build/build/build.eslint.config.js deleted file mode 100644 index a179d08..0000000 --- a/packages/build/build/build.eslint.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./default.eslint.config')(require('./build').from()); diff --git a/packages/build/build/build.js b/packages/build/build/build.js index 1d280b3..61b3b08 100644 --- a/packages/build/build/build.js +++ b/packages/build/build/build.js @@ -186,15 +186,24 @@ module.exports = class Build extends Flecks { } const rootConfig = await this.resolver.resolve(join(this.root, 'build', config)); if (rootConfig) { + debugSilly("resolved '%s' to '%s'", config, rootConfig); return rootConfig; } if (override) { const overrideConfig = await this.resolver.resolve(join(override, 'build', config)); if (overrideConfig) { + debugSilly("resolved '%s' to '%s'", config, overrideConfig); return overrideConfig; } } - return this.resolver.resolve(join(fleck, 'build', config)); + const fleckConfig = await this.resolver.resolve(join(fleck, 'build', config)); + if (fleckConfig) { + debugSilly("resolved '%s' to '%s'", config, fleckConfig); + } + else { + throw new Error(`couldn't resolve '${config}'`); + } + return fleckConfig; } async runtimeCompiler(runtime, config, env, argv) { diff --git a/packages/build/build/build.test.webpack.config.js b/packages/build/build/build.test.webpack.config.js deleted file mode 100644 index 361e327..0000000 --- a/packages/build/build/build.test.webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const Build = require('./build'); -const configFn = require('./test.webpack.config'); - -module.exports = async (env, argv) => { - const flecks = await Build.from(); - const config = await configFn(env, argv, flecks); - return config; -}; diff --git a/packages/build/build/build.webpack.config.js b/packages/build/build/build.webpack.config.js deleted file mode 100644 index dff3508..0000000 --- a/packages/build/build/build.webpack.config.js +++ /dev/null @@ -1,17 +0,0 @@ -const Build = require('./build'); -const configFn = require('./fleck.webpack.config'); -const {ProcessAssets, processFleckAssets} = require('./process-assets'); -const {executable} = require('./webpack'); - -module.exports = async (env, argv) => { - const flecks = await Build.from(); - const config = await configFn(env, argv, flecks); - config.plugins.push(new ProcessAssets('fleck', flecks)); - // Small hack because internals. - flecks.hooks['@flecks/build.processAssets'] = [{ - fleck: '@flecks/build', - fn: (target, assets, compilation) => processFleckAssets(assets, compilation), - }]; - config.plugins.push(executable()); - return config; -}; diff --git a/packages/build/build/cli.js b/packages/build/build/cli.js index db18024..6a9fbb3 100755 --- a/packages/build/build/cli.js +++ b/packages/build/build/cli.js @@ -34,7 +34,7 @@ const program = new Command(); program .enablePositionalOptions() .name('flecks') - .usage('[command] [...]'); + .usage(' [...]'); // Bootstrap. (async () => { debugSilly('bootstrapping flecks...'); @@ -43,6 +43,9 @@ program // Register commands. const commands = await flecks.invokeMergeUniqueAsync('@flecks/build.commands', program); const keys = Object.keys(commands).sort(); + if (0 === keys.length) { + program.error('No flecks commands defined! You probably forgot to install packages in this project.'); + } for (let i = 0; i < keys.length; ++i) { const { action, @@ -63,5 +66,5 @@ program cmd.action(forwardProcessCode(action)); } // Parse commandline. - program.parse(process.argv); + await program.parseAsync(process.argv); })(); diff --git a/packages/build/build/commands.js b/packages/build/build/commands.js index 1b05b6d..ebcd98a 100644 --- a/packages/build/build/commands.js +++ b/packages/build/build/commands.js @@ -2,7 +2,6 @@ const { access, constants: {R_OK, W_OK}, readFile, - writeFile, } = require('fs/promises'); const { dirname, @@ -27,6 +26,7 @@ const { loadYml, lockFile, spawnWith, + writeFile, } = require('@flecks/core/src/server'); const chokidar = require('chokidar'); const {glob} = require('glob'); @@ -230,14 +230,15 @@ exports.commands = (program, flecks) => { '--mode', (production && !hot) ? 'production' : 'development', ]; const options = { + // @todo This kills the pnpm. Let's use a real IPC channel. + useFork: true, + ...rest, env: { FLECKS_BUILD_IS_PRODUCTION: production, ...(target ? {FLECKS_CORE_BUILD_LIST: target} : {}), ...(hot ? {FLECKS_ENV__flecks_server__hot: 'true'} : {}), + ...rest.env, }, - // @todo This kills the pnpm. Let's use a real IPC channel. - useFork: true, - ...rest, }; if (!watch) { return spawnWith(cmd, options); diff --git a/packages/build/build/explicate.js b/packages/build/build/explicate.js index d9cf01b..4e87d39 100644 --- a/packages/build/build/explicate.js +++ b/packages/build/build/explicate.js @@ -53,7 +53,9 @@ module.exports = async function explicate( resolver.addAlias(join(submodules, 'webpack'), join(resolver.root, 'node_modules', 'webpack')); // Runtime NODE_PATH hacking. const {env} = process; - env.NODE_PATH = (env.NODE_PATH || '') + delimiter + submodules; + const nodePaths = env.NODE_PATH ? env.NODE_PATH.split(delimiter) : []; + nodePaths.push(submodules); + env.NODE_PATH = nodePaths.join(delimiter); // eslint-disable-next-line no-underscore-dangle Module._initPaths(); } diff --git a/packages/build/build/resolver.js b/packages/build/build/resolver.js index 52e789e..7177f64 100644 --- a/packages/build/build/resolver.js +++ b/packages/build/build/resolver.js @@ -1,4 +1,4 @@ -const {join} = require('path'); +const {delimiter, join} = require('path'); const D = require('@flecks/core/build/debug'); const {CachedInputFileSystem, ResolverFactory} = require('enhanced-resolve'); @@ -28,6 +28,14 @@ module.exports = class Resolver { root = FLECKS_CORE_ROOT, ...rest } = options; + const {NODE_PATH} = process.env; + if (NODE_PATH) { + NODE_PATH.split(delimiter).forEach((path) => { + if (!modules.includes(path)) { + modules.push(path); + } + }); + } this.resolver = ResolverFactory.createResolver({ conditionNames: ['node'], extensions: ['.js', '.json', '.node'], diff --git a/packages/build/build/test.webpack.config.js b/packages/build/build/test.webpack.config.js index dfc46fa..0ac3eac 100644 --- a/packages/build/build/test.webpack.config.js +++ b/packages/build/build/test.webpack.config.js @@ -12,6 +12,7 @@ const configFn = require('./common.webpack.config'); const { FLECKS_CORE_ROOT = process.cwd(), + FLECKS_CORE_TEST_PLATFORMS, } = process.env; const tests = join(FLECKS_CORE_ROOT, 'test'); @@ -20,9 +21,13 @@ module.exports = async (env, argv, flecks) => { const config = await configFn(env, argv, flecks); config.output.chunkFormat = false; config.output.path = join(FLECKS_CORE_ROOT, 'dist', 'test'); - // Test entry. - const testPaths = await glob(join(tests, '*.js')); - const {platforms} = flecks; + const testPaths = []; + const platforms = FLECKS_CORE_TEST_PLATFORMS + ? JSON.parse(FLECKS_CORE_TEST_PLATFORMS) + : [...new Set(['default', ...flecks.platforms])]; + if (platforms.includes('default')) { + testPaths.push(...await glob(join(tests, '*.js'))); + } testPaths.push( ...(await Promise.all(platforms.map((platform) => glob(join(tests, platform, '*.js'))))) .flat(), diff --git a/packages/build/package.json b/packages/build/package.json index d097c3d..cc93e34 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -4,12 +4,10 @@ "author": "cha0s", "license": "MIT", "scripts": { - "build": "webpack --config ./build/build.webpack.config.js --mode production", + "build": "flecks build", "clean": "rm -rf dist node_modules yarn.lock", - "lint": "eslint --config ./build/eslint.config.js .", - "postversion": "npm run build", - "test": "webpack --config ./build/build.test.webpack.config.js --mode production && mocha --colors --parallel ./dist/test/*.js ./dist/test/server/*.js", - "test:watch": "webpack watch --config ./build/build.test.webpack.config.js --mode development & mocha --colors --parallel --watch --watch-files ./dist/test/*.js ./dist/test/server/*.js" + "lint": "flecks lint", + "test": "flecks test" }, "repository": { "type": "git", diff --git a/packages/build/test/server/lint.js b/packages/build/test/e2e/lint.js similarity index 100% rename from packages/build/test/server/lint.js rename to packages/build/test/e2e/lint.js diff --git a/packages/build/test/server/cli-no-commands.js b/packages/build/test/server/cli-no-commands.js new file mode 100644 index 0000000..4c3a87b --- /dev/null +++ b/packages/build/test/server/cli-no-commands.js @@ -0,0 +1,30 @@ +import {join} from 'path'; + +import {createWorkspace} from '@flecks/core/build/testing'; +import { + binaryPath, + pipesink, + processCode, + spawnWith, + writeFile, +} from '@flecks/core/server'; +import {expect} from 'chai'; + +it('fails predictably if no commands are defined', async () => { + const workspace = await createWorkspace(); + await writeFile(join(workspace, 'package.json'), '{}'); + const child = spawnWith( + [await binaryPath('flecks', '@flecks/build')], + { + stdio: 'pipe', + env: { + FLECKS_CORE_ROOT: workspace, + }, + }, + ); + const buffer = await pipesink(child.stderr); + expect(await processCode(child)) + .to.equal(1); + expect(buffer.toString()) + .to.contain('No flecks commands defined'); +}); diff --git a/packages/build/test/server/explicate.js b/packages/build/test/server/explicate.js index 85efcc7..a902c7e 100644 --- a/packages/build/test/server/explicate.js +++ b/packages/build/test/server/explicate.js @@ -1,10 +1,11 @@ -import {mkdir, writeFile} from 'fs/promises'; +import {mkdir} from 'fs/promises'; import {join} from 'path'; import {expect} from 'chai'; import explicate from '@flecks/build/build/explicate'; import Resolver from '@flecks/build/build/resolver'; +import {writeFile} from '@flecks/core/server'; const { FLECKS_CORE_ROOT = process.cwd(), diff --git a/packages/build/test/server/resolver-node-path.js b/packages/build/test/server/resolver-node-path.js new file mode 100644 index 0000000..1017029 --- /dev/null +++ b/packages/build/test/server/resolver-node-path.js @@ -0,0 +1,17 @@ +import {join} from 'path'; + +import Resolver from '@flecks/build/build/resolver'; +import {createWorkspace} from '@flecks/core/build/testing'; +import {writeFile} from '@flecks/core/server'; +import {expect} from 'chai'; + +it('uses NODE_PATH when resolving', async () => { + const workspace = await createWorkspace(); + await writeFile(join(workspace, 'nothing'), ''); + const {NODE_PATH} = process.env; + process.env.NODE_PATH = workspace; + const resolver = new Resolver(); + expect(await resolver.resolve('nothing')) + .to.not.be.undefined; + process.env.NODE_PATH = NODE_PATH; +}); diff --git a/packages/build/test/server/yml.js b/packages/build/test/server/yml.js index 9a0090e..c120b41 100644 --- a/packages/build/test/server/yml.js +++ b/packages/build/test/server/yml.js @@ -1,7 +1,7 @@ import addPathsToYml from '@flecks/core/build/add-paths-to-yml'; -import {loadYml} from '@flecks/core/server'; +import {loadYml, writeFile} from '@flecks/core/server'; import {expect} from 'chai'; -import {readFile, writeFile} from 'fs/promises'; +import {readFile} from 'fs/promises'; it('can add paths to YML', async () => { await writeFile( diff --git a/packages/core/build/add-paths-to-yml.js b/packages/core/build/add-paths-to-yml.js index f289724..3d608eb 100644 --- a/packages/core/build/add-paths-to-yml.js +++ b/packages/core/build/add-paths-to-yml.js @@ -1,8 +1,10 @@ -const {readFile, writeFile} = require('fs/promises'); +const {readFile} = require('fs/promises'); const {join} = require('path'); const {dump: dumpYml, load: loadYml} = require('js-yaml'); +const {writeFile} = require('../src/server/fs'); + const { FLECKS_CORE_ROOT = process.cwd(), } = process.env; diff --git a/packages/core/build/core.eslint.config.js b/packages/core/build/core.eslint.config.js deleted file mode 100644 index 1bfd462..0000000 --- a/packages/core/build/core.eslint.config.js +++ /dev/null @@ -1,74 +0,0 @@ -const globals = require('globals'); - -module.exports = ({ - extends: [ - require.resolve('eslint-config-airbnb'), - require.resolve('eslint-config-airbnb/hooks'), - ], - globals: { - ...globals.browser, - ...globals.es2021, - ...globals.mocha, - ...globals.node, - __non_webpack_require__: true, - }, - ignorePatterns: [ - 'dist/**', - // Not even gonna try. - 'build/flecks.hooks.js', - ], - overrides: [ - { - files: [ - 'build/**/*.js', - ], - rules: { - 'import/no-extraneous-dependencies': ['error', {devDependencies: true}], - 'import/no-dynamic-require': 'off', - 'global-require': 'off', - }, - }, - { - files: [ - 'test/**/*.js', - ], - rules: { - 'brace-style': 'off', - 'class-methods-use-this': 'off', - 'import/no-extraneous-dependencies': 'off', - 'import/no-unresolved': 'off', - 'max-classes-per-file': 'off', - 'no-new': 'off', - 'no-unused-expressions': 'off', - 'padded-blocks': 'off', - }, - }, - ], - parser: require.resolve('@babel/eslint-parser'), - parserOptions: { - requireConfigFile: false, - }, - plugins: ['@babel'], - rules: { - 'brace-style': ['error', 'stroustrup'], - // Bug: https://github.com/import-js/eslint-plugin-import/issues/2181 - 'import/no-import-module-exports': 'off', - 'import/prefer-default-export': 'off', - 'jsx-a11y/control-has-associated-label': ['error', {assert: 'either'}], - 'jsx-a11y/label-has-associated-control': ['error', {assert: 'either'}], - 'no-param-reassign': ['error', {props: false}], - 'no-plusplus': 'off', - 'no-shadow': 'off', - 'object-curly-spacing': 'off', - 'padded-blocks': ['error', {classes: 'always'}], - yoda: 'off', - }, - settings: { - 'import/resolver': { - node: {}, - }, - react: { - version: '18.2.0', - }, - }, -}); diff --git a/packages/core/build/core.webpack.config.js b/packages/core/build/core.webpack.config.js deleted file mode 100644 index d8df2e0..0000000 --- a/packages/core/build/core.webpack.config.js +++ /dev/null @@ -1,15 +0,0 @@ -const Build = require('../../build/build/build'); -const configFn = require('../../build/build/fleck.webpack.config'); -const {ProcessAssets, processFleckAssets} = require('../../build/build/process-assets'); - -module.exports = async (env, argv) => { - const flecks = await Build.from(); - const config = await configFn(env, argv, flecks); - config.plugins.push(new ProcessAssets('fleck', flecks)); - // Small hack because internals. - flecks.hooks['@flecks/build.processAssets'] = [{ - fleck: '@flecks/build', - fn: (target, assets, compilation) => processFleckAssets(assets, compilation), - }]; - return config; -}; diff --git a/packages/core/build/stream.js b/packages/core/build/stream.js index e4f269b..adeb2f7 100644 --- a/packages/core/build/stream.js +++ b/packages/core/build/stream.js @@ -1,7 +1,8 @@ // eslint-disable-next-line max-classes-per-file +const {Buffer} = require('buffer'); const {dump: dumpYml, load: loadYml} = require('js-yaml'); const JsonParse = require('jsonparse'); -const {Transform} = require('stream'); +const {Transform, Writable} = require('stream'); exports.JsonStream = class JsonStream extends Transform { @@ -45,6 +46,33 @@ exports.JsonStream.PrettyPrint = class extends exports.JsonStream { }; +exports.pipesink = (streamsOrStream) => { + const streams = Array.isArray(streamsOrStream) ? streamsOrStream : [streamsOrStream]; + class Sink extends Writable { + + constructor() { + super(); + this.buffers = []; + } + + // eslint-disable-next-line no-underscore-dangle + _write(chunk, encoding, done) { + this.buffers.push(chunk); + done(); + } + + } + const sink = new Sink(); + const final = streams.reduce((output, input) => input.pipe(output)); + return new Promise((resolve, reject) => { + final.pipe(sink); + final.on('error', reject); + final.on('end', () => { + resolve(Buffer.concat(sink.buffers)); + }); + }); +}; + exports.YamlStream = class YamlStream extends Transform { constructor(decorator, options = {dump: {}, load: {}}) { diff --git a/packages/core/build/test.webpack.config.js b/packages/core/build/test.webpack.config.js deleted file mode 100644 index d6615da..0000000 --- a/packages/core/build/test.webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const Build = require('../../build/build/build'); -const configFn = require('../../build/build/test.webpack.config'); - -module.exports = async (env, argv) => { - const flecks = await Build.from(); - const config = await configFn(env, argv, flecks); - return config; -}; diff --git a/packages/core/build/testing.js b/packages/core/build/testing.js new file mode 100644 index 0000000..78cc972 --- /dev/null +++ b/packages/core/build/testing.js @@ -0,0 +1,31 @@ +import {randomBytes} from 'crypto'; +import {mkdir} from 'fs/promises'; +import {tmpdir} from 'os'; +import {join} from 'path'; + +import {rimraf} from 'rimraf'; + +export function id() { + return new Promise((resolve, reject) => { + randomBytes(16, (error, bytes) => (error ? reject(error) : resolve(bytes.toString('hex')))); + }); +} + +export async function createWorkspace() { + const workspace = join(tmpdir(), '@flecks', 'core', 'testing', await id()); + await mkdir(workspace, {recursive: true}); + // sheeeeesh + process.prependListener('message', async (message) => { + if ('__workerpool-terminate__' === message) { + rimraf.sync(workspace); + } + }); + return workspace; +} + +export function heavySetup(fn) { + return function heavySetup() { + this.timeout(0); + return fn(); + }; +} diff --git a/packages/core/package.json b/packages/core/package.json index 7c1a984..6085cf4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -4,12 +4,10 @@ "author": "cha0s", "license": "MIT", "scripts": { - "build": "webpack --config ./build/core.webpack.config.js --mode production", - "clean": "rm -rf dist node_modules yarn.lock", - "lint": "eslint --config ./build/core.eslint.config.js .", - "postversion": "npm run build", - "test": "webpack --config ./build/test.webpack.config.js --mode production && mocha --colors --parallel ./dist/test/*.js ./dist/test/server/*.js", - "test:watch": "webpack watch --config ./build/test.webpack.config.js --mode development & mocha --colors --parallel --watch --watch-files ./dist/test/*.js ./dist/test/server/*.js" + "build": "flecks build", + "clean": "flecks clean", + "lint": "flecks lint", + "test": "flecks test" }, "repository": { "type": "git", diff --git a/packages/core/src/server/fs.js b/packages/core/src/server/fs.js new file mode 100644 index 0000000..cdeb0f1 --- /dev/null +++ b/packages/core/src/server/fs.js @@ -0,0 +1,17 @@ +const {open, writeFile} = require('fs/promises'); + +exports.writeFile = async ( + path, + content, + paramaterizedOptions, +) => { + const options = { + flags: 'w', + mode: 0o666, + ...paramaterizedOptions, + }; + const filehandle = await open(path, options.flags, options.mode); + await writeFile(filehandle, content, options); + await filehandle.sync(); + await filehandle.close(); +}; diff --git a/packages/core/src/server/index.js b/packages/core/src/server/index.js index 2397c05..c134d63 100644 --- a/packages/core/src/server/index.js +++ b/packages/core/src/server/index.js @@ -7,6 +7,7 @@ module.exports = { glob: require('glob').glob, loadYml, ...require('../../build/stream'), + ...require('./fs'), ...require('./package-manager'), ...require('./process'), }; diff --git a/packages/core/src/server/package-manager.js b/packages/core/src/server/package-manager.js index f3345e9..137cfa8 100644 --- a/packages/core/src/server/package-manager.js +++ b/packages/core/src/server/package-manager.js @@ -25,7 +25,7 @@ exports.build = async ({cwd, packageManager = exports.inferPackageManager()}) => break; default: } - return args && processCode(spawnWith(args, {cwd})); + return args && processCode(spawnWith(args, {cwd, env: {FLECKS_CORE_ROOT: cwd}})); }; exports.add = async ({dev, packageManager = exports.inferPackageManager(), packages}) => { diff --git a/packages/core/src/server/process.js b/packages/core/src/server/process.js index acf8035..fa38149 100644 --- a/packages/core/src/server/process.js +++ b/packages/core/src/server/process.js @@ -1,4 +1,4 @@ -const {fork, spawn} = require('child_process'); +const {exec, fork, spawn} = require('child_process'); const { access, constants: {X_OK}, @@ -41,6 +41,22 @@ exports.processCode = (child) => new Promise((resolve, reject) => { }); }); +exports.run = (cmd, {suppressError = true} = {}) => ( + new Promise((resolve) => { + exec(cmd, (error, stdout) => { + if (error) { + if (!suppressError) { + // eslint-disable-next-line no-console + console.error(error); + } + resolve(undefined); + return; + } + resolve(stdout.trim()); + }); + }) +); + const children = []; exports.spawnWith = (cmd, opts = {}) => { diff --git a/packages/core/test/server/write-files.js b/packages/core/test/server/write-files.js new file mode 100644 index 0000000..63f2f5c --- /dev/null +++ b/packages/core/test/server/write-files.js @@ -0,0 +1,17 @@ +/* eslint-disable camelcase */ + +import {access} from 'fs/promises'; +import {join} from 'path'; + +import {createWorkspace} from '@flecks/core/build/testing'; +import {writeFile} from '@flecks/core/server'; + +it('writes files', async () => { + const workspace = await createWorkspace(); + /* eslint-disable no-await-in-loop */ + for (let i = 0; i < 10; ++i) { + const path = join(workspace, `${i}`); + await writeFile(path, ''); + await access(path); + } +}); diff --git a/packages/create-app/build/cli.js b/packages/create-app/build/cli.js index dc565c3..9a8db0a 100755 --- a/packages/create-app/build/cli.js +++ b/packages/create-app/build/cli.js @@ -33,13 +33,16 @@ const { try { await stat(destination); const error = new Error( - `@flecks/create-app: destination '${destination} already exists: aborting`, + `@flecks/create-app: destination '${destination}' already exists: aborting`, ); - error.code = 129; + error.code = 1; throw error; } - // eslint-disable-next-line no-empty - catch (error) {} + catch (error) { + if ('ENOENT' !== error.code) { + throw error; + } + } const fileTree = await move(name, join(__dirname, '..', 'template')); fileTree.pipe( 'build/flecks.yml', @@ -50,12 +53,17 @@ const { ); // Write the tree. await fileTree.writeTo(destination); - await install({cwd: destination, packageManager}); - await build({cwd: destination, packageManager}); + if (0 !== await install({cwd: destination, packageManager})) { + throw new Error('installation failed'); + } + if (0 !== await build({cwd: destination, packageManager})) { + throw new Error('build failed'); + } } catch (error) { // eslint-disable-next-line no-console - console.error(error); + console.error('creation failed:', error); + process.exitCode = 1; } }); await program.parseAsync(process.argv); diff --git a/packages/create-app/test/e2e/npm.js b/packages/create-app/test/e2e/npm.js new file mode 100644 index 0000000..385c0d3 --- /dev/null +++ b/packages/create-app/test/e2e/npm.js @@ -0,0 +1,30 @@ +import {join} from 'path'; + +import {createWorkspace} from '@flecks/core/build/testing'; +import {processCode, spawnWith} from '@flecks/core/server'; +import {expect} from 'chai'; + +const { + FLECKS_CORE_ROOT = process.cwd(), +} = process.env; + +it('generates a working application with npm', async () => { + const workspace = await createWorkspace(); + const child = spawnWith( + [join(FLECKS_CORE_ROOT, 'build', 'cli.js'), 'test-application'], + { + env: { + FLECKS_CORE_ROOT: workspace, + PATCH_PACKAGE_INTEGRATION_TEST: 1, + }, + stdio: 'ignore', + }, + ); + expect(await processCode(child)) + .to.equal(0); + expect(await processCode(spawnWith( + ['node', join(workspace, 'test-application', 'dist', 'server')], + {stdio: 'ignore'}, + ))) + .to.equal(0); +}); diff --git a/packages/create-app/test/server/basics.js b/packages/create-app/test/server/basics.js new file mode 100644 index 0000000..f7605d1 --- /dev/null +++ b/packages/create-app/test/server/basics.js @@ -0,0 +1,19 @@ +import {join} from 'path'; + +import {pipesink, processCode, spawnWith} from '@flecks/core/server'; +import {expect} from 'chai'; + +const { + FLECKS_CORE_ROOT = process.cwd(), +} = process.env; + +it('shows help text', async () => { + const child = spawnWith( + [join(FLECKS_CORE_ROOT, 'build', 'cli.js'), '--help'], + {stdio: 'pipe'}, + ); + const buffer = await pipesink(child.stdout); + await processCode(child); + expect(buffer.toString()) + .to.contain('display help for command'); +}); diff --git a/packages/create-app/test/server/failure-already-exists.js b/packages/create-app/test/server/failure-already-exists.js new file mode 100644 index 0000000..13c104e --- /dev/null +++ b/packages/create-app/test/server/failure-already-exists.js @@ -0,0 +1,27 @@ +import {mkdir} from 'fs/promises'; +import {join} from 'path'; + +import {createWorkspace} from '@flecks/core/build/testing'; +import {pipesink, processCode, spawnWith} from '@flecks/core/server'; +import {expect} from 'chai'; + +const { + FLECKS_CORE_ROOT = process.cwd(), +} = process.env; + +it('fails if destination already exists', async () => { + const workspace = await createWorkspace(); + await mkdir(join(workspace, 'failure'), {recursive: true}); + const child = spawnWith( + [join(FLECKS_CORE_ROOT, 'build', 'cli.js'), 'failure'], + { + env: {FLECKS_CORE_ROOT: workspace}, + stdio: 'pipe', + }, + ); + const buffer = await pipesink(child.stderr); + expect(await processCode(child)) + .to.equal(1); + expect(buffer.toString()) + .to.contain(`destination '${join(workspace, 'failure')}' already exists`); +}); diff --git a/packages/create-app/test/server/failure-invalid-name.js b/packages/create-app/test/server/failure-invalid-name.js new file mode 100644 index 0000000..ad1e5b1 --- /dev/null +++ b/packages/create-app/test/server/failure-invalid-name.js @@ -0,0 +1,20 @@ +import {join} from 'path'; + +import {pipesink, processCode, spawnWith} from '@flecks/core/server'; +import {expect} from 'chai'; + +const { + FLECKS_CORE_ROOT = process.cwd(), +} = process.env; + +it('fails on invalid name', async () => { + const child = spawnWith( + [join(FLECKS_CORE_ROOT, 'build', 'cli.js'), "'R%@#'"], + {stdio: 'pipe'}, + ); + const buffer = await pipesink(child.stderr); + expect(await processCode(child)) + .to.equal(1); + expect(buffer.toString()) + .to.contain('invalid app name'); +}); diff --git a/packages/create-fleck/build/cli.js b/packages/create-fleck/build/cli.js index e663b5b..31ebaf1 100755 --- a/packages/create-fleck/build/cli.js +++ b/packages/create-fleck/build/cli.js @@ -92,6 +92,7 @@ const { catch (error) { // eslint-disable-next-line no-console console.error('creation failed:', error); + process.exitCode = 1; } }); await program.parseAsync(process.argv); diff --git a/packages/create-fleck/package.json b/packages/create-fleck/package.json index be2152c..8b841de 100644 --- a/packages/create-fleck/package.json +++ b/packages/create-fleck/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/create-fleck/template/package.json.noconflict b/packages/create-fleck/template/package.json.noconflict index c1a8cc9..192e04b 100644 --- a/packages/create-fleck/template/package.json.noconflict +++ b/packages/create-fleck/template/package.json.noconflict @@ -4,7 +4,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "files": [ diff --git a/packages/db/package.json b/packages/db/package.json index 92410b6..07a051a 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/docker/package.json b/packages/docker/package.json index aa78624..0bbd066 100644 --- a/packages/docker/package.json +++ b/packages/docker/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/electron/package.json b/packages/electron/package.json index 8c58657..09cb2d7 100644 --- a/packages/electron/package.json +++ b/packages/electron/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/fleck/build/commands.js b/packages/fleck/build/commands.js index 28b0c07..09b31bc 100644 --- a/packages/fleck/build/commands.js +++ b/packages/fleck/build/commands.js @@ -22,9 +22,11 @@ module.exports = (program, flecks) => { ], options: [ program.createOption('-d, --no-production', 'dev build'), + program.createOption('-p, --platform [platforms...]', 'platforms to test') + .default(['default', 'server']), program.createOption('-t, --timeout ', 'timeout').default(2000), - program.createOption('-w, --watch', 'watch for changes'), program.createOption('-v, --verbose', 'verbose output'), + program.createOption('-w, --watch', 'watch for changes'), ], description: [ 'Run tests.', @@ -33,21 +35,29 @@ module.exports = (program, flecks) => { ].join('\n'), action: async (only, opts) => { const { + platform: platforms, production, timeout, watch, } = opts; const {build} = coreCommands(program, flecks); - const tests = await glob(join(FLECKS_CORE_ROOT, 'test', '*.js')); - const serverTests = await glob(join(FLECKS_CORE_ROOT, 'test', 'server', '*.js')); - let files = [] - .concat(tests, serverTests) - .map((path) => relative(FLECKS_CORE_ROOT, path)); + let files = []; + if (platforms.includes('default')) { + files.push(...await glob(join(FLECKS_CORE_ROOT, 'test', '*.js'))); + } + await Promise.all( + platforms + .filter((platform) => 'default' !== platform) + .map(async (platform) => { + files.push(...await glob(join(FLECKS_CORE_ROOT, 'test', platform, '*.js'))); + }), + ); if (0 === files.length) { // eslint-disable-next-line no-console console.log('No tests found.'); return undefined; } + files = files.map((path) => relative(FLECKS_CORE_ROOT, path)); if (only) { if (files.includes(only)) { files = [only]; @@ -60,7 +70,15 @@ module.exports = (program, flecks) => { // Remove the previous test. await rimraf(join(FLECKS_CORE_ROOT, 'dist', 'test')); // Kick off building the test and wait for the file to exist. - await build.action('test', {production, stdio: 'ignore', watch}); + await build.action( + 'test', + { + env: {FLECKS_CORE_TEST_PLATFORMS: JSON.stringify(platforms)}, + production, + stdio: 'ignore', + watch, + }, + ); debug('Testing...', opts); // eslint-disable-next-line no-constant-condition while (true) { diff --git a/packages/passport-local-react/package.json b/packages/passport-local-react/package.json index 0ff00f2..dd3bca6 100644 --- a/packages/passport-local-react/package.json +++ b/packages/passport-local-react/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/passport-local/package.json b/packages/passport-local/package.json index feaaa31..6c16b04 100644 --- a/packages/passport-local/package.json +++ b/packages/passport-local/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/passport-react/package.json b/packages/passport-react/package.json index 955f054..9179cbe 100644 --- a/packages/passport-react/package.json +++ b/packages/passport-react/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/passport/package.json b/packages/passport/package.json index 2f14094..5a70cda 100644 --- a/packages/passport/package.json +++ b/packages/passport/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/react/package.json b/packages/react/package.json index db61225..97de014 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "postinstall": "node src/fake-context.js", "test": "flecks test" }, diff --git a/packages/redis/package.json b/packages/redis/package.json index 175ac06..9d8512a 100644 --- a/packages/redis/package.json +++ b/packages/redis/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/redux/package.json b/packages/redux/package.json index b9d5685..583f7a9 100644 --- a/packages/redux/package.json +++ b/packages/redux/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/repl/package.json b/packages/repl/package.json index b5f7cdc..e11f3bd 100644 --- a/packages/repl/package.json +++ b/packages/repl/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/server/package.json b/packages/server/package.json index 7d6609b..7f2f4f8 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/server/test/server/build-dev.js b/packages/server/test/server/build-dev.js index 118a79d..f18b19d 100644 --- a/packages/server/test/server/build-dev.js +++ b/packages/server/test/server/build-dev.js @@ -1,14 +1,16 @@ import {access} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {createApplication, build} from './build/build'; -it('builds for development', async () => { +let artifact; + +before(heavySetup(async () => { const path = await createApplication(); await build(path, {args: ['-d']}); - let artifact; try { await access(join(path, 'dist', 'server', 'index.js')); artifact = true; @@ -16,6 +18,9 @@ it('builds for development', async () => { catch (error) { artifact = false; } +})); + +it('builds for development', async () => { expect(artifact) .to.be.true; }); diff --git a/packages/server/test/server/build-production.js b/packages/server/test/server/build-production.js index 89e0fae..ac00241 100644 --- a/packages/server/test/server/build-production.js +++ b/packages/server/test/server/build-production.js @@ -1,14 +1,16 @@ import {access} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {createApplication, build} from './build/build'; -it('builds for production', async () => { +let artifact; + +before(heavySetup(async () => { const path = await createApplication(); await build(path); - let artifact; try { await access(join(path, 'dist', 'server', 'index.js')); artifact = true; @@ -16,6 +18,9 @@ it('builds for production', async () => { catch (error) { artifact = false; } +})); + +it('builds for production', async () => { expect(artifact) .to.be.true; }); diff --git a/packages/server/test/server/build/build.js b/packages/server/test/server/build/build.js index 9184817..bee23f7 100644 --- a/packages/server/test/server/build/build.js +++ b/packages/server/test/server/build/build.js @@ -1,45 +1,36 @@ -import {cp, mkdir} from 'fs/promises'; +import {cp} from 'fs/promises'; import {join} from 'path'; -import {rimraf} from '@flecks/build/server'; +import {createWorkspace} from '@flecks/core/build/testing'; import {binaryPath, processCode, spawnWith} from '@flecks/core/server'; -import id from './id'; import {listen} from './listen'; const { FLECKS_CORE_ROOT = process.cwd(), } = process.env; -export const applications = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'server'); export const template = join(FLECKS_CORE_ROOT, 'test', 'server', 'template'); export async function createApplication() { - const path = join(applications, await id()); - await rimraf(path); - await mkdir(path, {recursive: true}); - await cp(template, path, {recursive: true}); - // sheeeeesh - process.prependListener('message', async (message) => { - if ('__workerpool-terminate__' === message) { - rimraf.sync(path); - } - }); - return path; + const workspace = await createWorkspace(); + await cp(template, workspace, {recursive: true}); + return workspace; } export async function buildChild(path, {args = [], opts = {}} = {}) { return spawnWith( [await binaryPath('flecks', '@flecks/build'), 'build', ...args], { + stdio: 'ignore', ...opts, env: { FLECKS_ENV__flecks_server__stats: '{"preset": "none"}', FLECKS_ENV__flecks_server__start: 0, FLECKS_CORE_ROOT: path, + NODE_PATH: join(FLECKS_CORE_ROOT, '..', '..', 'node_modules'), ...opts.env, }, - stdio: 'ignore', }, ); } @@ -56,6 +47,7 @@ export async function serverActions(path, actions) { { env: { FLECKS_SERVER_TEST_SOCKET: socketPath, + NODE_PATH: join(FLECKS_CORE_ROOT, '..', '..', 'node_modules'), }, stdio: 'ignore', }, diff --git a/packages/server/test/server/build/id.js b/packages/server/test/server/build/id.js deleted file mode 100644 index e900c05..0000000 --- a/packages/server/test/server/build/id.js +++ /dev/null @@ -1,7 +0,0 @@ -import {randomBytes} from 'crypto'; - -export default function id() { - return new Promise((resolve, reject) => { - randomBytes(16, (error, bytes) => (error ? reject(error) : resolve(bytes.toString('hex')))); - }); -} diff --git a/packages/server/test/server/build/listen.js b/packages/server/test/server/build/listen.js index 44f1e53..6999d74 100644 --- a/packages/server/test/server/build/listen.js +++ b/packages/server/test/server/build/listen.js @@ -3,7 +3,7 @@ import {createServer} from 'net'; import {tmpdir} from 'os'; import {dirname, join} from 'path'; -import id from './id'; +import {id} from '@flecks/core/build/testing'; class SocketWrapper { diff --git a/packages/server/test/server/config-fail.js b/packages/server/test/server/config-fail.js index 784da41..2e734f6 100644 --- a/packages/server/test/server/config-fail.js +++ b/packages/server/test/server/config-fail.js @@ -1,13 +1,17 @@ -import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; +import {writeFile} from '@flecks/core/server'; import {expect} from 'chai'; import {build, createApplication} from './build/build'; import {socketListener} from './build/listen'; -it('updates config', async () => { - const path = await createApplication(); +let path; +let socket; + +before(heavySetup(async () => { + path = await createApplication(); const {socketPath, socketServer} = await socketListener(); build( path, @@ -21,7 +25,10 @@ it('updates config', async () => { }, }, ); - const socket = await socketServer.waitForSocket(); + socket = await socketServer.waitForSocket(); +})); + +it('updates config', async () => { expect((await socket.send({type: 'config.get', payload: 'comm.foo'})).payload) .to.equal('bar'); await writeFile( diff --git a/packages/server/test/server/config-restart.js b/packages/server/test/server/config-restart.js index d712b5d..3d684e9 100644 --- a/packages/server/test/server/config-restart.js +++ b/packages/server/test/server/config-restart.js @@ -1,14 +1,20 @@ -import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; +import {writeFile} from '@flecks/core/server'; import {expect} from 'chai'; import {buildChild, createApplication} from './build/build'; import {socketListener} from './build/listen'; -it('restarts when config keys change', async () => { - const path = await createApplication(); - const {socketPath, socketServer} = await socketListener(); +let path; +let listener; +let socket; + +before(heavySetup(async () => { + path = await createApplication(); + listener = await socketListener(); + const {socketPath, socketServer} = listener; await buildChild( path, { @@ -21,7 +27,11 @@ it('restarts when config keys change', async () => { }, }, ); - const socket = await socketServer.waitForSocket(); + socket = await socketServer.waitForSocket(); +})); + +async function restart() { + this.timeout(0); let restarted; const whatHappened = Promise.race([ socket.waitForHmr() @@ -50,10 +60,15 @@ it('restarts when config keys change', async () => { expect(restarted) .to.be.true; let config; - await socketServer.waitForSocket() + const before = Date.now(); + await listener.socketServer.waitForSocket() .then(async (socket) => { ({payload: config} = await socket.send({type: 'config.get', payload: '@flecks/repl/server'})); }); + // Had to rebuild... + this.timeout(2000 + (Date.now() - before)); expect(config) .to.not.be.undefined; -}); +} + +it('restarts when config keys change', restart); diff --git a/packages/server/test/server/config-update.js b/packages/server/test/server/config-update.js index 05537d6..44eb943 100644 --- a/packages/server/test/server/config-update.js +++ b/packages/server/test/server/config-update.js @@ -1,13 +1,17 @@ -import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; +import {writeFile} from '@flecks/core/server'; import {expect} from 'chai'; import {build, createApplication} from './build/build'; import {socketListener} from './build/listen'; -it('updates config', async () => { - const path = await createApplication(); +let path; +let socket; + +before(heavySetup(async () => { + path = await createApplication(); const {socketPath, socketServer} = await socketListener(); build( path, @@ -21,7 +25,10 @@ it('updates config', async () => { }, }, ); - const socket = await socketServer.waitForSocket(); + socket = await socketServer.waitForSocket(); +})); + +it('updates config', async () => { expect((await socket.send({type: 'config.get', payload: '@flecks/core.id'})).payload) .to.equal('flecks'); await writeFile( diff --git a/packages/server/test/server/runtime-config-bootstrap.js b/packages/server/test/server/runtime-config-bootstrap.js index 5dccf60..e9b08ce 100644 --- a/packages/server/test/server/runtime-config-bootstrap.js +++ b/packages/server/test/server/runtime-config-bootstrap.js @@ -1,12 +1,16 @@ -import {mkdir, writeFile} from 'fs/promises'; +import {mkdir} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; +import {writeFile} from '@flecks/core/server'; import {expect} from 'chai'; import {build, createApplication, serverActions} from './build/build'; -it('propagates bootstrap config', async () => { - const path = await createApplication(); +let path; + +before(heavySetup(async () => { + path = await createApplication(); await mkdir(join(path, 'server-only', 'build'), {recursive: true}); await writeFile(join(path, 'server-only', 'package.json'), '{}'); const config = ` @@ -29,6 +33,9 @@ it('propagates bootstrap config', async () => { `, ); await build(path, {args: ['-d']}); +})); + +it('propagates bootstrap config', async () => { const {results: [{payload: foo}, {payload: blah}]} = await serverActions(path, [ {type: 'config.get', payload: 'server-only.foo'}, {type: 'config.get', payload: 'server-only.blah'}, diff --git a/packages/server/test/server/runtime-config-override.js b/packages/server/test/server/runtime-config-override.js index 908bd17..a6d106b 100644 --- a/packages/server/test/server/runtime-config-override.js +++ b/packages/server/test/server/runtime-config-override.js @@ -1,12 +1,15 @@ -import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; +import {writeFile} from '@flecks/core/server'; import {expect} from 'chai'; import {build, createApplication, serverActions} from './build/build'; -it('propagates bootstrap config', async () => { - const path = await createApplication(); +let path; + +before(heavySetup(async () => { + path = await createApplication(); await writeFile( join(path, 'build', 'flecks.yml'), ` @@ -17,6 +20,9 @@ it('propagates bootstrap config', async () => { `, ); await build(path, {args: ['-d']}); +})); + +it('propagates bootstrap config', async () => { const {results: [{payload: id}, {payload: foo}]} = await serverActions(path, [ {type: 'config.get', payload: '@flecks/core.id'}, {type: 'config.get', payload: 'comm.foo'}, diff --git a/packages/server/test/server/runtime-config-runtime.js b/packages/server/test/server/runtime-config-runtime.js index a9f80e8..f6f6ee9 100644 --- a/packages/server/test/server/runtime-config-runtime.js +++ b/packages/server/test/server/runtime-config-runtime.js @@ -1,10 +1,16 @@ +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {build, createApplication, serverActions} from './build/build'; -it('propagates runtime config', async () => { - const path = await createApplication(); +let path; + +before(heavySetup(async () => { + path = await createApplication(); await build(path, {args: ['-d']}); +})); + +it('propagates runtime config', async () => { const {results: [{payload: foo}]} = await serverActions(path, [ {type: 'config.get', payload: 'comm.foo'}, {type: 'exit'}, diff --git a/packages/server/test/server/runtime-connect.js b/packages/server/test/server/runtime-connect.js index d2fe59d..9dea1c4 100644 --- a/packages/server/test/server/runtime-connect.js +++ b/packages/server/test/server/runtime-connect.js @@ -1,10 +1,16 @@ +import {heavySetup} from '@flecks/core/build/testing'; import {expect} from 'chai'; import {build, createApplication, serverActions} from './build/build'; -it('connects', async () => { - const path = await createApplication(); +let path; + +before(heavySetup(async () => { + path = await createApplication(); await build(path, {args: ['-d']}); +})); + +it('connects', async () => { const {code} = await serverActions(path, [ {type: 'exit', payload: 42}, ]); diff --git a/packages/server/test/server/source-restart.js b/packages/server/test/server/source-restart.js index 94173d3..f902fda 100644 --- a/packages/server/test/server/source-restart.js +++ b/packages/server/test/server/source-restart.js @@ -1,13 +1,17 @@ -import {writeFile} from 'fs/promises'; import {join} from 'path'; +import {heavySetup} from '@flecks/core/build/testing'; +import {writeFile} from '@flecks/core/server'; import {expect} from 'chai'; import {buildChild, createApplication} from './build/build'; import {socketListener} from './build/listen'; -it('restarts when root sources change', async () => { - const path = await createApplication(); +let path; +let socket; + +before(heavySetup(async () => { + path = await createApplication(); const {socketPath, socketServer} = await socketListener(); await buildChild( path, @@ -21,7 +25,10 @@ it('restarts when root sources change', async () => { }, }, ); - const socket = await socketServer.waitForSocket(); + socket = await socketServer.waitForSocket(); +})); + +it('restarts when root sources change', async () => { let restarted; const whatHappened = Promise.race([ socket.waitForHmr() diff --git a/packages/session/package.json b/packages/session/package.json index f1b9749..9250989 100644 --- a/packages/session/package.json +++ b/packages/session/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/socket/package.json b/packages/socket/package.json index a26f3e6..a87e4cd 100644 --- a/packages/socket/package.json +++ b/packages/socket/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/packages/web/package.json b/packages/web/package.json index 460c5d9..a63bcdb 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -7,7 +7,6 @@ "build": "flecks build", "clean": "flecks clean", "lint": "flecks lint", - "postversion": "npm run build", "test": "flecks test" }, "repository": { diff --git a/website b/website index a353767..813bc11 160000 --- a/website +++ b/website @@ -1 +1 @@ -Subproject commit a353767791b7cff7b47057ec4cfb7651bb12e020 +Subproject commit 813bc11d09557e9fb25126ceb7041f130c36551e