test: many upgrades

This commit is contained in:
cha0s 2024-02-10 16:48:40 -06:00
commit ece82c8159
71 changed files with 613 additions and 365 deletions

22
.github/workflows/ci.yml vendored Normal file
View File

@ -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

12
.github/workflows/e2e.yml vendored Normal file
View File

@ -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

View File

@ -1,14 +1,14 @@
name: CI name: Continuous Integration
on: on:
push: workflow_call:
branches: [master] inputs:
pull_request: run:
branches: [master] required: true
workflow_dispatch: {} type: string
jobs: jobs:
verify: node:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
@ -20,7 +20,8 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'npm' cache: 'npm'
- run: npm ${{ vars.NPM_CI_FLAGS }} ci - run: npm config set registry ${{ vars.NPM_CI_REGISTRY }}
- run: npm run lint if: ${{ vars.NPM_CI_REGISTRY }}
- run: npm run test - run: |
- run: npm run build npm ci
${{ inputs.run }}

View File

@ -2,12 +2,14 @@ const {Buffer} = require('buffer');
const {exec} = require('child_process'); const {exec} = require('child_process');
const {createHash} = require('crypto'); const {createHash} = require('crypto');
const {createReadStream} = require('fs'); const {createReadStream} = require('fs');
const {cp, mkdir, writeFile} = require('fs/promises'); const {cp, mkdir} = require('fs/promises');
const {join} = require('path'); const {join} = require('path');
const { const {
processCode, processCode,
run,
spawnWith, spawnWith,
writeFile,
} = require('@flecks/core/src/server'); } = require('@flecks/core/src/server');
const Arborist = require('@npmcli/arborist'); const Arborist = require('@npmcli/arborist');
const {glob} = require('glob'); const {glob} = require('glob');
@ -25,18 +27,6 @@ const localVersions = {};
const packCache = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'publish'); const packCache = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'publish');
const {workspaces} = require(join(FLECKS_CORE_ROOT, 'package.json')); 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. // Get integrity sums for creator dependencies.
const packPkg = async (pkg) => { const packPkg = async (pkg) => {
await processCode(spawnWith( await processCode(spawnWith(

194
package-lock.json generated
View File

@ -16237,7 +16237,7 @@
}, },
"packages/build": { "packages/build": {
"name": "@flecks/build", "name": "@flecks/build",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/core": "^7.12.10", "@babel/core": "^7.12.10",
@ -16248,7 +16248,7 @@
"@babel/preset-env": "^7.12.11", "@babel/preset-env": "^7.12.11",
"@babel/traverse": "^7.17.0", "@babel/traverse": "^7.17.0",
"@babel/types": "^7.17.0", "@babel/types": "^7.17.0",
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"babel-loader": "^9.1.3", "babel-loader": "^9.1.3",
"babel-merge": "^3.0.0", "babel-merge": "^3.0.0",
"chai": "4.2.0", "chai": "4.2.0",
@ -16305,7 +16305,7 @@
}, },
"packages/core": { "packages/core": {
"name": "@flecks/core", "name": "@flecks/core",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "4.3.1", "debug": "4.3.1",
@ -16360,10 +16360,10 @@
}, },
"packages/create-app": { "packages/create-app": {
"name": "@flecks/create-app", "name": "@flecks/create-app",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"commander": "11.1.0", "commander": "11.1.0",
"validate-npm-package-name": "^3.0.0" "validate-npm-package-name": "^3.0.0"
}, },
@ -16371,8 +16371,8 @@
"create-app": "build/cli.js" "create-app": "build/cli.js"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/create-app/node_modules/builtins": { "packages/create-app/node_modules/builtins": {
@ -16390,45 +16390,45 @@
}, },
"packages/create-fleck": { "packages/create-fleck": {
"name": "@flecks/create-fleck", "name": "@flecks/create-fleck",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"commander": "11.1.0" "commander": "11.1.0"
}, },
"bin": { "bin": {
"create-fleck": "build/cli.js" "create-fleck": "build/cli.js"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/db": { "packages/db": {
"name": "@flecks/db", "name": "@flecks/db",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"sequelize": "^6.3.5", "sequelize": "^6.3.5",
"sqlite3": "^5.0.2" "sqlite3": "^5.0.2"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/docker": { "packages/docker": {
"name": "@flecks/docker", "name": "@flecks/docker",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"debug": "^4.3.3" "debug": "^4.3.3"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/docker/node_modules/debug": { "packages/docker/node_modules/debug": {
@ -16449,47 +16449,47 @@
}, },
"packages/dox": { "packages/dox": {
"name": "@flecks/dox", "name": "@flecks/dox",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/core": "^7.17.2", "@babel/core": "^7.17.2",
"@babel/traverse": "^7.17.0", "@babel/traverse": "^7.17.0",
"@babel/types": "^7.17.0", "@babel/types": "^7.17.0",
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"comment-parser": "^1.3.0", "comment-parser": "^1.3.0",
"rimraf": "^5.0.5" "rimraf": "^5.0.5"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/electron": { "packages/electron": {
"name": "@flecks/electron", "name": "@flecks/electron",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"electron": "^28.1.4", "electron": "^28.1.4",
"electron-devtools-installer": "^3.2.0" "electron-devtools-installer": "^3.2.0"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/fleck": { "packages/fleck": {
"name": "@flecks/fleck", "name": "@flecks/fleck",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"babel-merge": "^3.0.0", "babel-merge": "^3.0.0",
"debug": "^4.3.3", "debug": "^4.3.3",
"mocha": "^10.2.0" "mocha": "^10.2.0"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"chai": "4.2.0" "chai": "4.2.0"
} }
}, },
@ -16511,75 +16511,75 @@
}, },
"packages/passport": { "packages/passport": {
"name": "@flecks/passport", "name": "@flecks/passport",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@flecks/db": "^4.0.2", "@flecks/db": "^4.0.5",
"@flecks/redux": "^4.0.2", "@flecks/redux": "^4.0.5",
"@flecks/session": "^4.0.2", "@flecks/session": "^4.0.5",
"passport": "^0.7.0" "passport": "^0.7.0"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/passport-local": { "packages/passport-local": {
"name": "@flecks/passport-local", "name": "@flecks/passport-local",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@flecks/passport": "^4.0.2", "@flecks/passport": "^4.0.5",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"passport-local": "^1.0.0" "passport-local": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/passport-local-react": { "packages/passport-local-react": {
"name": "@flecks/passport-local-react", "name": "@flecks/passport-local-react",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@flecks/passport-local": "^4.0.2", "@flecks/passport-local": "^4.0.5",
"@flecks/passport-react": "^4.0.2", "@flecks/passport-react": "^4.0.5",
"@flecks/react": "^4.0.2" "@flecks/react": "^4.0.5"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/passport-react": { "packages/passport-react": {
"name": "@flecks/passport-react", "name": "@flecks/passport-react",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@flecks/passport": "^4.0.2", "@flecks/passport": "^4.0.5",
"@flecks/react": "^4.0.2", "@flecks/react": "^4.0.5",
"@flecks/react-redux": "^4.0.2", "@flecks/react-redux": "^4.0.5",
"@flecks/web": "^4.0.2" "@flecks/web": "^4.0.5"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/react": { "packages/react": {
"name": "@flecks/react", "name": "@flecks/react",
"version": "4.0.2", "version": "4.0.5",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/preset-react": "^7.23.3", "@babel/preset-react": "^7.23.3",
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@flecks/web": "^4.0.2", "@flecks/web": "^4.0.5",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
"babel-merge": "^3.0.0", "babel-merge": "^3.0.0",
"classnames": "^2.3.1", "classnames": "^2.3.1",
@ -16595,55 +16595,55 @@
"redux-first-history": "5.1.1" "redux-first-history": "5.1.1"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/react-redux": { "packages/react-redux": {
"name": "@flecks/react-redux", "name": "@flecks/react-redux",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@flecks/react": "^4.0.2", "@flecks/react": "^4.0.5",
"@flecks/redux": "^4.0.2", "@flecks/redux": "^4.0.5",
"react-redux": "^7.2.2" "react-redux": "^7.2.2"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/redis": { "packages/redis": {
"name": "@flecks/redis", "name": "@flecks/redis",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@socket.io/redis-adapter": "7.1.0", "@socket.io/redis-adapter": "7.1.0",
"connect-redis": "^5.0.0", "connect-redis": "^5.0.0",
"express-session": "^1.17.1", "express-session": "^1.17.1",
"redis": "4.0.3" "redis": "4.0.3"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/redux": { "packages/redux": {
"name": "@flecks/redux", "name": "@flecks/redux",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@reduxjs/toolkit": "^1.5.0", "@reduxjs/toolkit": "^1.5.0",
"debug": "^4.3.3", "debug": "^4.3.3",
"lodash.throttle": "^4.1.1", "lodash.throttle": "^4.1.1",
"reduce-reducers": "^1.0.4" "reduce-reducers": "^1.0.4"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/redux/node_modules/debug": { "packages/redux/node_modules/debug": {
@ -16664,51 +16664,51 @@
}, },
"packages/repl": { "packages/repl": {
"name": "@flecks/repl", "name": "@flecks/repl",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"command-exists": "^1.2.9", "command-exists": "^1.2.9",
"debug": "4.3.1" "debug": "4.3.1"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/server": { "packages/server": {
"name": "@flecks/server", "name": "@flecks/server",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2" "@flecks/core": "^4.0.5"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/session": { "packages/session": {
"name": "@flecks/session", "name": "@flecks/session",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"express": "^4.18.2", "express": "^4.18.2",
"express-session": "^1.17.3" "express-session": "^1.17.3"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/socket": { "packages/socket": {
"name": "@flecks/socket", "name": "@flecks/socket",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@flecks/react": "^4.0.2", "@flecks/react": "^4.0.5",
"msgpack-lite": "^0.1.26", "msgpack-lite": "^0.1.26",
"proxy-addr": "^2.0.6", "proxy-addr": "^2.0.6",
"schemapack": "^1.4.2", "schemapack": "^1.4.2",
@ -16716,18 +16716,18 @@
"socket.io-client": "^4.1.2" "socket.io-client": "^4.1.2"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
}, },
"packages/web": { "packages/web": {
"name": "@flecks/web", "name": "@flecks/web",
"version": "4.0.2", "version": "4.0.5",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@babel/parser": "^7.17.0", "@babel/parser": "^7.17.0",
"@babel/types": "^7.17.0", "@babel/types": "^7.17.0",
"@flecks/core": "^4.0.2", "@flecks/core": "^4.0.5",
"@webpack-cli/serve": "^2.0.5", "@webpack-cli/serve": "^2.0.5",
"add-asset-html-webpack-plugin": "^6.0.0", "add-asset-html-webpack-plugin": "^6.0.0",
"assert": "^2.1.0", "assert": "^2.1.0",
@ -16759,8 +16759,8 @@
"webpack-dev-server": "^4.15.1" "webpack-dev-server": "^4.15.1"
}, },
"devDependencies": { "devDependencies": {
"@flecks/build": "^4.0.2", "@flecks/build": "^4.0.5",
"@flecks/fleck": "^4.0.2" "@flecks/fleck": "^4.0.5"
} }
} }
} }

View File

@ -8,14 +8,14 @@
}, },
"scripts": { "scripts": {
"build": "node build/tasks npm run build", "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: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: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: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", "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", "lint": "node build/tasks npm run lint",
"publish": "node build/publish --provenance", "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": [ "workspaces": [
"packages/*" "packages/*"

View File

@ -1 +0,0 @@
module.exports = require('./default.eslint.config')(require('./build').from());

View File

@ -186,15 +186,24 @@ module.exports = class Build extends Flecks {
} }
const rootConfig = await this.resolver.resolve(join(this.root, 'build', config)); const rootConfig = await this.resolver.resolve(join(this.root, 'build', config));
if (rootConfig) { if (rootConfig) {
debugSilly("resolved '%s' to '%s'", config, rootConfig);
return rootConfig; return rootConfig;
} }
if (override) { if (override) {
const overrideConfig = await this.resolver.resolve(join(override, 'build', config)); const overrideConfig = await this.resolver.resolve(join(override, 'build', config));
if (overrideConfig) { if (overrideConfig) {
debugSilly("resolved '%s' to '%s'", config, overrideConfig);
return 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) { async runtimeCompiler(runtime, config, env, argv) {

View File

@ -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;
};

View File

@ -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;
};

View File

@ -34,7 +34,7 @@ const program = new Command();
program program
.enablePositionalOptions() .enablePositionalOptions()
.name('flecks') .name('flecks')
.usage('[command] [...]'); .usage('<command> [...]');
// Bootstrap. // Bootstrap.
(async () => { (async () => {
debugSilly('bootstrapping flecks...'); debugSilly('bootstrapping flecks...');
@ -43,6 +43,9 @@ program
// Register commands. // Register commands.
const commands = await flecks.invokeMergeUniqueAsync('@flecks/build.commands', program); const commands = await flecks.invokeMergeUniqueAsync('@flecks/build.commands', program);
const keys = Object.keys(commands).sort(); 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) { for (let i = 0; i < keys.length; ++i) {
const { const {
action, action,
@ -63,5 +66,5 @@ program
cmd.action(forwardProcessCode(action)); cmd.action(forwardProcessCode(action));
} }
// Parse commandline. // Parse commandline.
program.parse(process.argv); await program.parseAsync(process.argv);
})(); })();

View File

@ -2,7 +2,6 @@ const {
access, access,
constants: {R_OK, W_OK}, constants: {R_OK, W_OK},
readFile, readFile,
writeFile,
} = require('fs/promises'); } = require('fs/promises');
const { const {
dirname, dirname,
@ -27,6 +26,7 @@ const {
loadYml, loadYml,
lockFile, lockFile,
spawnWith, spawnWith,
writeFile,
} = require('@flecks/core/src/server'); } = require('@flecks/core/src/server');
const chokidar = require('chokidar'); const chokidar = require('chokidar');
const {glob} = require('glob'); const {glob} = require('glob');
@ -230,14 +230,15 @@ exports.commands = (program, flecks) => {
'--mode', (production && !hot) ? 'production' : 'development', '--mode', (production && !hot) ? 'production' : 'development',
]; ];
const options = { const options = {
// @todo This kills the pnpm. Let's use a real IPC channel.
useFork: true,
...rest,
env: { env: {
FLECKS_BUILD_IS_PRODUCTION: production, FLECKS_BUILD_IS_PRODUCTION: production,
...(target ? {FLECKS_CORE_BUILD_LIST: target} : {}), ...(target ? {FLECKS_CORE_BUILD_LIST: target} : {}),
...(hot ? {FLECKS_ENV__flecks_server__hot: 'true'} : {}), ...(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) { if (!watch) {
return spawnWith(cmd, options); return spawnWith(cmd, options);

View File

@ -53,7 +53,9 @@ module.exports = async function explicate(
resolver.addAlias(join(submodules, 'webpack'), join(resolver.root, 'node_modules', 'webpack')); resolver.addAlias(join(submodules, 'webpack'), join(resolver.root, 'node_modules', 'webpack'));
// Runtime NODE_PATH hacking. // Runtime NODE_PATH hacking.
const {env} = process; 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 // eslint-disable-next-line no-underscore-dangle
Module._initPaths(); Module._initPaths();
} }

View File

@ -1,4 +1,4 @@
const {join} = require('path'); const {delimiter, join} = require('path');
const D = require('@flecks/core/build/debug'); const D = require('@flecks/core/build/debug');
const {CachedInputFileSystem, ResolverFactory} = require('enhanced-resolve'); const {CachedInputFileSystem, ResolverFactory} = require('enhanced-resolve');
@ -28,6 +28,14 @@ module.exports = class Resolver {
root = FLECKS_CORE_ROOT, root = FLECKS_CORE_ROOT,
...rest ...rest
} = options; } = 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({ this.resolver = ResolverFactory.createResolver({
conditionNames: ['node'], conditionNames: ['node'],
extensions: ['.js', '.json', '.node'], extensions: ['.js', '.json', '.node'],

View File

@ -12,6 +12,7 @@ const configFn = require('./common.webpack.config');
const { const {
FLECKS_CORE_ROOT = process.cwd(), FLECKS_CORE_ROOT = process.cwd(),
FLECKS_CORE_TEST_PLATFORMS,
} = process.env; } = process.env;
const tests = join(FLECKS_CORE_ROOT, 'test'); const tests = join(FLECKS_CORE_ROOT, 'test');
@ -20,9 +21,13 @@ module.exports = async (env, argv, flecks) => {
const config = await configFn(env, argv, flecks); const config = await configFn(env, argv, flecks);
config.output.chunkFormat = false; config.output.chunkFormat = false;
config.output.path = join(FLECKS_CORE_ROOT, 'dist', 'test'); config.output.path = join(FLECKS_CORE_ROOT, 'dist', 'test');
// Test entry. const testPaths = [];
const testPaths = await glob(join(tests, '*.js')); const platforms = FLECKS_CORE_TEST_PLATFORMS
const {platforms} = flecks; ? JSON.parse(FLECKS_CORE_TEST_PLATFORMS)
: [...new Set(['default', ...flecks.platforms])];
if (platforms.includes('default')) {
testPaths.push(...await glob(join(tests, '*.js')));
}
testPaths.push( testPaths.push(
...(await Promise.all(platforms.map((platform) => glob(join(tests, platform, '*.js'))))) ...(await Promise.all(platforms.map((platform) => glob(join(tests, platform, '*.js')))))
.flat(), .flat(),

View File

@ -4,12 +4,10 @@
"author": "cha0s", "author": "cha0s",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"build": "webpack --config ./build/build.webpack.config.js --mode production", "build": "flecks build",
"clean": "rm -rf dist node_modules yarn.lock", "clean": "rm -rf dist node_modules yarn.lock",
"lint": "eslint --config ./build/eslint.config.js .", "lint": "flecks lint",
"postversion": "npm run build", "test": "flecks test"
"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"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -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');
});

View File

@ -1,10 +1,11 @@
import {mkdir, writeFile} from 'fs/promises'; import {mkdir} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {expect} from 'chai'; import {expect} from 'chai';
import explicate from '@flecks/build/build/explicate'; import explicate from '@flecks/build/build/explicate';
import Resolver from '@flecks/build/build/resolver'; import Resolver from '@flecks/build/build/resolver';
import {writeFile} from '@flecks/core/server';
const { const {
FLECKS_CORE_ROOT = process.cwd(), FLECKS_CORE_ROOT = process.cwd(),

View File

@ -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;
});

View File

@ -1,7 +1,7 @@
import addPathsToYml from '@flecks/core/build/add-paths-to-yml'; 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 {expect} from 'chai';
import {readFile, writeFile} from 'fs/promises'; import {readFile} from 'fs/promises';
it('can add paths to YML', async () => { it('can add paths to YML', async () => {
await writeFile( await writeFile(

View File

@ -1,8 +1,10 @@
const {readFile, writeFile} = require('fs/promises'); const {readFile} = require('fs/promises');
const {join} = require('path'); const {join} = require('path');
const {dump: dumpYml, load: loadYml} = require('js-yaml'); const {dump: dumpYml, load: loadYml} = require('js-yaml');
const {writeFile} = require('../src/server/fs');
const { const {
FLECKS_CORE_ROOT = process.cwd(), FLECKS_CORE_ROOT = process.cwd(),
} = process.env; } = process.env;

View File

@ -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',
},
},
});

View File

@ -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;
};

View File

@ -1,7 +1,8 @@
// eslint-disable-next-line max-classes-per-file // eslint-disable-next-line max-classes-per-file
const {Buffer} = require('buffer');
const {dump: dumpYml, load: loadYml} = require('js-yaml'); const {dump: dumpYml, load: loadYml} = require('js-yaml');
const JsonParse = require('jsonparse'); const JsonParse = require('jsonparse');
const {Transform} = require('stream'); const {Transform, Writable} = require('stream');
exports.JsonStream = class JsonStream extends Transform { 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 { exports.YamlStream = class YamlStream extends Transform {
constructor(decorator, options = {dump: {}, load: {}}) { constructor(decorator, options = {dump: {}, load: {}}) {

View File

@ -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;
};

View File

@ -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();
};
}

View File

@ -4,12 +4,10 @@
"author": "cha0s", "author": "cha0s",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"build": "webpack --config ./build/core.webpack.config.js --mode production", "build": "flecks build",
"clean": "rm -rf dist node_modules yarn.lock", "clean": "flecks clean",
"lint": "eslint --config ./build/core.eslint.config.js .", "lint": "flecks lint",
"postversion": "npm run build", "test": "flecks test"
"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"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -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();
};

View File

@ -7,6 +7,7 @@ module.exports = {
glob: require('glob').glob, glob: require('glob').glob,
loadYml, loadYml,
...require('../../build/stream'), ...require('../../build/stream'),
...require('./fs'),
...require('./package-manager'), ...require('./package-manager'),
...require('./process'), ...require('./process'),
}; };

View File

@ -25,7 +25,7 @@ exports.build = async ({cwd, packageManager = exports.inferPackageManager()}) =>
break; break;
default: 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}) => { exports.add = async ({dev, packageManager = exports.inferPackageManager(), packages}) => {

View File

@ -1,4 +1,4 @@
const {fork, spawn} = require('child_process'); const {exec, fork, spawn} = require('child_process');
const { const {
access, access,
constants: {X_OK}, 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 = []; const children = [];
exports.spawnWith = (cmd, opts = {}) => { exports.spawnWith = (cmd, opts = {}) => {

View File

@ -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);
}
});

View File

@ -33,13 +33,16 @@ const {
try { try {
await stat(destination); await stat(destination);
const error = new Error( 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; 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')); const fileTree = await move(name, join(__dirname, '..', 'template'));
fileTree.pipe( fileTree.pipe(
'build/flecks.yml', 'build/flecks.yml',
@ -50,12 +53,17 @@ const {
); );
// Write the tree. // Write the tree.
await fileTree.writeTo(destination); await fileTree.writeTo(destination);
await install({cwd: destination, packageManager}); if (0 !== await install({cwd: destination, packageManager})) {
await build({cwd: destination, packageManager}); throw new Error('installation failed');
}
if (0 !== await build({cwd: destination, packageManager})) {
throw new Error('build failed');
}
} }
catch (error) { catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(error); console.error('creation failed:', error);
process.exitCode = 1;
} }
}); });
await program.parseAsync(process.argv); await program.parseAsync(process.argv);

View File

@ -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);
});

View File

@ -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');
});

View File

@ -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`);
});

View File

@ -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');
});

View File

@ -92,6 +92,7 @@ const {
catch (error) { catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error('creation failed:', error); console.error('creation failed:', error);
process.exitCode = 1;
} }
}); });
await program.parseAsync(process.argv); await program.parseAsync(process.argv);

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -4,7 +4,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"files": [ "files": [

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -22,9 +22,11 @@ module.exports = (program, flecks) => {
], ],
options: [ options: [
program.createOption('-d, --no-production', 'dev build'), program.createOption('-d, --no-production', 'dev build'),
program.createOption('-p, --platform [platforms...]', 'platforms to test')
.default(['default', 'server']),
program.createOption('-t, --timeout <ms>', 'timeout').default(2000), program.createOption('-t, --timeout <ms>', 'timeout').default(2000),
program.createOption('-w, --watch', 'watch for changes'),
program.createOption('-v, --verbose', 'verbose output'), program.createOption('-v, --verbose', 'verbose output'),
program.createOption('-w, --watch', 'watch for changes'),
], ],
description: [ description: [
'Run tests.', 'Run tests.',
@ -33,21 +35,29 @@ module.exports = (program, flecks) => {
].join('\n'), ].join('\n'),
action: async (only, opts) => { action: async (only, opts) => {
const { const {
platform: platforms,
production, production,
timeout, timeout,
watch, watch,
} = opts; } = opts;
const {build} = coreCommands(program, flecks); const {build} = coreCommands(program, flecks);
const tests = await glob(join(FLECKS_CORE_ROOT, 'test', '*.js')); let files = [];
const serverTests = await glob(join(FLECKS_CORE_ROOT, 'test', 'server', '*.js')); if (platforms.includes('default')) {
let files = [] files.push(...await glob(join(FLECKS_CORE_ROOT, 'test', '*.js')));
.concat(tests, serverTests) }
.map((path) => relative(FLECKS_CORE_ROOT, path)); 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) { if (0 === files.length) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log('No tests found.'); console.log('No tests found.');
return undefined; return undefined;
} }
files = files.map((path) => relative(FLECKS_CORE_ROOT, path));
if (only) { if (only) {
if (files.includes(only)) { if (files.includes(only)) {
files = [only]; files = [only];
@ -60,7 +70,15 @@ module.exports = (program, flecks) => {
// Remove the previous test. // Remove the previous test.
await rimraf(join(FLECKS_CORE_ROOT, 'dist', 'test')); await rimraf(join(FLECKS_CORE_ROOT, 'dist', 'test'));
// Kick off building the test and wait for the file to exist. // 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); debug('Testing...', opts);
// eslint-disable-next-line no-constant-condition // eslint-disable-next-line no-constant-condition
while (true) { while (true) {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"postinstall": "node src/fake-context.js", "postinstall": "node src/fake-context.js",
"test": "flecks test" "test": "flecks test"
}, },

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -1,14 +1,16 @@
import {access} from 'fs/promises'; import {access} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {expect} from 'chai'; import {expect} from 'chai';
import {createApplication, build} from './build/build'; import {createApplication, build} from './build/build';
it('builds for development', async () => { let artifact;
before(heavySetup(async () => {
const path = await createApplication(); const path = await createApplication();
await build(path, {args: ['-d']}); await build(path, {args: ['-d']});
let artifact;
try { try {
await access(join(path, 'dist', 'server', 'index.js')); await access(join(path, 'dist', 'server', 'index.js'));
artifact = true; artifact = true;
@ -16,6 +18,9 @@ it('builds for development', async () => {
catch (error) { catch (error) {
artifact = false; artifact = false;
} }
}));
it('builds for development', async () => {
expect(artifact) expect(artifact)
.to.be.true; .to.be.true;
}); });

View File

@ -1,14 +1,16 @@
import {access} from 'fs/promises'; import {access} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {expect} from 'chai'; import {expect} from 'chai';
import {createApplication, build} from './build/build'; import {createApplication, build} from './build/build';
it('builds for production', async () => { let artifact;
before(heavySetup(async () => {
const path = await createApplication(); const path = await createApplication();
await build(path); await build(path);
let artifact;
try { try {
await access(join(path, 'dist', 'server', 'index.js')); await access(join(path, 'dist', 'server', 'index.js'));
artifact = true; artifact = true;
@ -16,6 +18,9 @@ it('builds for production', async () => {
catch (error) { catch (error) {
artifact = false; artifact = false;
} }
}));
it('builds for production', async () => {
expect(artifact) expect(artifact)
.to.be.true; .to.be.true;
}); });

View File

@ -1,45 +1,36 @@
import {cp, mkdir} from 'fs/promises'; import {cp} from 'fs/promises';
import {join} from 'path'; 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 {binaryPath, processCode, spawnWith} from '@flecks/core/server';
import id from './id';
import {listen} from './listen'; import {listen} from './listen';
const { const {
FLECKS_CORE_ROOT = process.cwd(), FLECKS_CORE_ROOT = process.cwd(),
} = process.env; } = 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 const template = join(FLECKS_CORE_ROOT, 'test', 'server', 'template');
export async function createApplication() { export async function createApplication() {
const path = join(applications, await id()); const workspace = await createWorkspace();
await rimraf(path); await cp(template, workspace, {recursive: true});
await mkdir(path, {recursive: true}); return workspace;
await cp(template, path, {recursive: true});
// sheeeeesh
process.prependListener('message', async (message) => {
if ('__workerpool-terminate__' === message) {
rimraf.sync(path);
}
});
return path;
} }
export async function buildChild(path, {args = [], opts = {}} = {}) { export async function buildChild(path, {args = [], opts = {}} = {}) {
return spawnWith( return spawnWith(
[await binaryPath('flecks', '@flecks/build'), 'build', ...args], [await binaryPath('flecks', '@flecks/build'), 'build', ...args],
{ {
stdio: 'ignore',
...opts, ...opts,
env: { env: {
FLECKS_ENV__flecks_server__stats: '{"preset": "none"}', FLECKS_ENV__flecks_server__stats: '{"preset": "none"}',
FLECKS_ENV__flecks_server__start: 0, FLECKS_ENV__flecks_server__start: 0,
FLECKS_CORE_ROOT: path, FLECKS_CORE_ROOT: path,
NODE_PATH: join(FLECKS_CORE_ROOT, '..', '..', 'node_modules'),
...opts.env, ...opts.env,
}, },
stdio: 'ignore',
}, },
); );
} }
@ -56,6 +47,7 @@ export async function serverActions(path, actions) {
{ {
env: { env: {
FLECKS_SERVER_TEST_SOCKET: socketPath, FLECKS_SERVER_TEST_SOCKET: socketPath,
NODE_PATH: join(FLECKS_CORE_ROOT, '..', '..', 'node_modules'),
}, },
stdio: 'ignore', stdio: 'ignore',
}, },

View File

@ -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'))));
});
}

View File

@ -3,7 +3,7 @@ import {createServer} from 'net';
import {tmpdir} from 'os'; import {tmpdir} from 'os';
import {dirname, join} from 'path'; import {dirname, join} from 'path';
import id from './id'; import {id} from '@flecks/core/build/testing';
class SocketWrapper { class SocketWrapper {

View File

@ -1,13 +1,17 @@
import {writeFile} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai'; import {expect} from 'chai';
import {build, createApplication} from './build/build'; import {build, createApplication} from './build/build';
import {socketListener} from './build/listen'; import {socketListener} from './build/listen';
it('updates config', async () => { let path;
const path = await createApplication(); let socket;
before(heavySetup(async () => {
path = await createApplication();
const {socketPath, socketServer} = await socketListener(); const {socketPath, socketServer} = await socketListener();
build( build(
path, 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) expect((await socket.send({type: 'config.get', payload: 'comm.foo'})).payload)
.to.equal('bar'); .to.equal('bar');
await writeFile( await writeFile(

View File

@ -1,14 +1,20 @@
import {writeFile} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai'; import {expect} from 'chai';
import {buildChild, createApplication} from './build/build'; import {buildChild, createApplication} from './build/build';
import {socketListener} from './build/listen'; import {socketListener} from './build/listen';
it('restarts when config keys change', async () => { let path;
const path = await createApplication(); let listener;
const {socketPath, socketServer} = await socketListener(); let socket;
before(heavySetup(async () => {
path = await createApplication();
listener = await socketListener();
const {socketPath, socketServer} = listener;
await buildChild( await buildChild(
path, 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; let restarted;
const whatHappened = Promise.race([ const whatHappened = Promise.race([
socket.waitForHmr() socket.waitForHmr()
@ -50,10 +60,15 @@ it('restarts when config keys change', async () => {
expect(restarted) expect(restarted)
.to.be.true; .to.be.true;
let config; let config;
await socketServer.waitForSocket() const before = Date.now();
await listener.socketServer.waitForSocket()
.then(async (socket) => { .then(async (socket) => {
({payload: config} = await socket.send({type: 'config.get', payload: '@flecks/repl/server'})); ({payload: config} = await socket.send({type: 'config.get', payload: '@flecks/repl/server'}));
}); });
// Had to rebuild...
this.timeout(2000 + (Date.now() - before));
expect(config) expect(config)
.to.not.be.undefined; .to.not.be.undefined;
}); }
it('restarts when config keys change', restart);

View File

@ -1,13 +1,17 @@
import {writeFile} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai'; import {expect} from 'chai';
import {build, createApplication} from './build/build'; import {build, createApplication} from './build/build';
import {socketListener} from './build/listen'; import {socketListener} from './build/listen';
it('updates config', async () => { let path;
const path = await createApplication(); let socket;
before(heavySetup(async () => {
path = await createApplication();
const {socketPath, socketServer} = await socketListener(); const {socketPath, socketServer} = await socketListener();
build( build(
path, 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) expect((await socket.send({type: 'config.get', payload: '@flecks/core.id'})).payload)
.to.equal('flecks'); .to.equal('flecks');
await writeFile( await writeFile(

View File

@ -1,12 +1,16 @@
import {mkdir, writeFile} from 'fs/promises'; import {mkdir} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai'; import {expect} from 'chai';
import {build, createApplication, serverActions} from './build/build'; import {build, createApplication, serverActions} from './build/build';
it('propagates bootstrap config', async () => { let path;
const path = await createApplication();
before(heavySetup(async () => {
path = await createApplication();
await mkdir(join(path, 'server-only', 'build'), {recursive: true}); await mkdir(join(path, 'server-only', 'build'), {recursive: true});
await writeFile(join(path, 'server-only', 'package.json'), '{}'); await writeFile(join(path, 'server-only', 'package.json'), '{}');
const config = ` const config = `
@ -29,6 +33,9 @@ it('propagates bootstrap config', async () => {
`, `,
); );
await build(path, {args: ['-d']}); await build(path, {args: ['-d']});
}));
it('propagates bootstrap config', async () => {
const {results: [{payload: foo}, {payload: blah}]} = await serverActions(path, [ const {results: [{payload: foo}, {payload: blah}]} = await serverActions(path, [
{type: 'config.get', payload: 'server-only.foo'}, {type: 'config.get', payload: 'server-only.foo'},
{type: 'config.get', payload: 'server-only.blah'}, {type: 'config.get', payload: 'server-only.blah'},

View File

@ -1,12 +1,15 @@
import {writeFile} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai'; import {expect} from 'chai';
import {build, createApplication, serverActions} from './build/build'; import {build, createApplication, serverActions} from './build/build';
it('propagates bootstrap config', async () => { let path;
const path = await createApplication();
before(heavySetup(async () => {
path = await createApplication();
await writeFile( await writeFile(
join(path, 'build', 'flecks.yml'), join(path, 'build', 'flecks.yml'),
` `
@ -17,6 +20,9 @@ it('propagates bootstrap config', async () => {
`, `,
); );
await build(path, {args: ['-d']}); await build(path, {args: ['-d']});
}));
it('propagates bootstrap config', async () => {
const {results: [{payload: id}, {payload: foo}]} = await serverActions(path, [ const {results: [{payload: id}, {payload: foo}]} = await serverActions(path, [
{type: 'config.get', payload: '@flecks/core.id'}, {type: 'config.get', payload: '@flecks/core.id'},
{type: 'config.get', payload: 'comm.foo'}, {type: 'config.get', payload: 'comm.foo'},

View File

@ -1,10 +1,16 @@
import {heavySetup} from '@flecks/core/build/testing';
import {expect} from 'chai'; import {expect} from 'chai';
import {build, createApplication, serverActions} from './build/build'; import {build, createApplication, serverActions} from './build/build';
it('propagates runtime config', async () => { let path;
const path = await createApplication();
before(heavySetup(async () => {
path = await createApplication();
await build(path, {args: ['-d']}); await build(path, {args: ['-d']});
}));
it('propagates runtime config', async () => {
const {results: [{payload: foo}]} = await serverActions(path, [ const {results: [{payload: foo}]} = await serverActions(path, [
{type: 'config.get', payload: 'comm.foo'}, {type: 'config.get', payload: 'comm.foo'},
{type: 'exit'}, {type: 'exit'},

View File

@ -1,10 +1,16 @@
import {heavySetup} from '@flecks/core/build/testing';
import {expect} from 'chai'; import {expect} from 'chai';
import {build, createApplication, serverActions} from './build/build'; import {build, createApplication, serverActions} from './build/build';
it('connects', async () => { let path;
const path = await createApplication();
before(heavySetup(async () => {
path = await createApplication();
await build(path, {args: ['-d']}); await build(path, {args: ['-d']});
}));
it('connects', async () => {
const {code} = await serverActions(path, [ const {code} = await serverActions(path, [
{type: 'exit', payload: 42}, {type: 'exit', payload: 42},
]); ]);

View File

@ -1,13 +1,17 @@
import {writeFile} from 'fs/promises';
import {join} from 'path'; import {join} from 'path';
import {heavySetup} from '@flecks/core/build/testing';
import {writeFile} from '@flecks/core/server';
import {expect} from 'chai'; import {expect} from 'chai';
import {buildChild, createApplication} from './build/build'; import {buildChild, createApplication} from './build/build';
import {socketListener} from './build/listen'; import {socketListener} from './build/listen';
it('restarts when root sources change', async () => { let path;
const path = await createApplication(); let socket;
before(heavySetup(async () => {
path = await createApplication();
const {socketPath, socketServer} = await socketListener(); const {socketPath, socketServer} = await socketListener();
await buildChild( await buildChild(
path, 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; let restarted;
const whatHappened = Promise.race([ const whatHappened = Promise.race([
socket.waitForHmr() socket.waitForHmr()

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

View File

@ -7,7 +7,6 @@
"build": "flecks build", "build": "flecks build",
"clean": "flecks clean", "clean": "flecks clean",
"lint": "flecks lint", "lint": "flecks lint",
"postversion": "npm run build",
"test": "flecks test" "test": "flecks test"
}, },
"repository": { "repository": {

@ -1 +1 @@
Subproject commit a353767791b7cff7b47057ec4cfb7651bb12e020 Subproject commit 813bc11d09557e9fb25126ceb7041f130c36551e