@uscreen.de/create-fastify-app 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintcache +1 -1
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/main.yml +51 -0
- package/.gitignore +2 -0
- package/README.md +5 -0
- package/bin/cli.js +23 -49
- package/package.json +15 -5
- package/skeleton/.nvmrc +1 -1
- package/test/_arena/new-app/.editorconfig +13 -0
- package/test/_arena/new-app/.env.example +4 -0
- package/test/_arena/new-app/.envrc +4 -0
- package/test/_arena/new-app/.eslintrc +3 -0
- package/test/_arena/new-app/.gitignore +7 -0
- package/test/_arena/new-app/.gitlab-ci.yml.example +25 -0
- package/test/_arena/new-app/.husky/_/.gitignore +1 -0
- package/test/_arena/new-app/.nvmrc +1 -0
- package/test/_arena/new-app/.taprc +7 -0
- package/test/_arena/new-app/Makefile +11 -0
- package/test/_arena/new-app/README.md +38 -0
- package/test/_arena/new-app/app/app.js +17 -0
- package/test/_arena/new-app/app/config.js +34 -0
- package/test/_arena/new-app/app/plugins/noop.js +14 -0
- package/test/_arena/new-app/app/schemas.js +34 -0
- package/test/_arena/new-app/app/server.js +37 -0
- package/test/_arena/new-app/app/services/noop.js +22 -0
- package/test/_arena/new-app/package.json +40 -0
- package/test/_arena/new-app/test/app/noop.test.js +54 -0
- package/test/_arena/new-app/test/helper.js +29 -0
- package/test/cli.test.js +109 -0
- package/test/setup.js +33 -0
package/.eslintcache
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"/Users/
|
|
1
|
+
[{"/Users/martin/repos/uscreen/npm/create-fastify-app/bin/cli.js":"1","/Users/martin/repos/uscreen/npm/create-fastify-app/test/cli.test.js":"2","/Users/martin/repos/uscreen/npm/create-fastify-app/test/setup.js":"3"},{"size":3522,"mtime":1675168988666,"results":"4","hashOfConfig":"5"},{"size":2397,"mtime":1675169193473,"results":"6","hashOfConfig":"5"},{"size":717,"mtime":1675081403094,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","suppressedMessages":"10","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1ohqtje",{"filePath":"11","messages":"12","suppressedMessages":"13","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"14","messages":"15","suppressedMessages":"16","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/martin/repos/uscreen/npm/create-fastify-app/bin/cli.js",[],[],"/Users/martin/repos/uscreen/npm/create-fastify-app/test/cli.test.js",[],[],"/Users/martin/repos/uscreen/npm/create-fastify-app/test/setup.js",[],[]]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "npm"
|
|
9
|
+
directory: "/"
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
|
|
3
|
+
|
|
4
|
+
name: Test CI
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: ["master"]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: ["master"]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
node-version: [14, 16, 18, 19]
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout code
|
|
20
|
+
uses: actions/checkout@v3
|
|
21
|
+
|
|
22
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
23
|
+
uses: actions/setup-node@v3
|
|
24
|
+
with:
|
|
25
|
+
node-version: ${{ matrix.node-version }}
|
|
26
|
+
cache: "npm"
|
|
27
|
+
|
|
28
|
+
- name: Install packages
|
|
29
|
+
run: npm install
|
|
30
|
+
|
|
31
|
+
- name: Run tests
|
|
32
|
+
run: npm run test:ci
|
|
33
|
+
|
|
34
|
+
- name: Coveralls
|
|
35
|
+
uses: coverallsapp/github-action@master
|
|
36
|
+
with:
|
|
37
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
38
|
+
|
|
39
|
+
automerge:
|
|
40
|
+
if: >
|
|
41
|
+
github.event_name == 'pull_request' &&
|
|
42
|
+
github.event.pull_request.user.login == 'dependabot[bot]'
|
|
43
|
+
needs: test
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
permissions:
|
|
46
|
+
pull-requests: write
|
|
47
|
+
contents: write
|
|
48
|
+
steps:
|
|
49
|
+
- uses: fastify/github-action-merge-dependabot@v3
|
|
50
|
+
with:
|
|
51
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
package/.gitignore
CHANGED
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# create-fastify-app
|
|
2
2
|
|
|
3
|
+
[](https://github.com/uscreen/create-fastify-app/actions/workflows/main.yml)
|
|
4
|
+
[](https://coveralls.io/github/uscreen/create-fastify-app?branch=master)
|
|
5
|
+
[](https://snyk.io/test/github/uscreen/create-fastify-app?targetFile=package.json)
|
|
6
|
+
[](https://badge.fury.io/js/@uscreen.de%2Fcreate-fastify-app)
|
|
7
|
+
|
|
3
8
|
> cli to quickly bootstrap a new fastify-app
|
|
4
9
|
|
|
5
10
|
This package provides the cli skript to create a new `@uscreen.de/fastify-app` from scratch. No need to install any other prerequisites than node and yarn. Features include:
|
package/bin/cli.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import path from 'path'
|
|
4
4
|
import { fileURLToPath } from 'url'
|
|
5
|
+
import { createRequire } from 'module'
|
|
6
|
+
|
|
5
7
|
import { program } from 'commander'
|
|
6
8
|
import { readPackageUpSync } from 'read-pkg-up'
|
|
7
9
|
import { writePackage } from 'write-pkg'
|
|
@@ -11,6 +13,8 @@ import { spawn } from 'child_process'
|
|
|
11
13
|
|
|
12
14
|
const __filename = fileURLToPath(import.meta.url)
|
|
13
15
|
const __dirname = path.dirname(__filename)
|
|
16
|
+
const require = createRequire(import.meta.url)
|
|
17
|
+
const { version } = require('../package.json')
|
|
14
18
|
|
|
15
19
|
let root
|
|
16
20
|
let skeleton
|
|
@@ -25,6 +29,7 @@ const initializeGitRepository = (path) =>
|
|
|
25
29
|
git.stderr.on('data', (data) => process.stderr.write(data))
|
|
26
30
|
git.on('close', (code) => {
|
|
27
31
|
if (code === 0) return resolve(code)
|
|
32
|
+
/* c8 ignore next */
|
|
28
33
|
reject(code)
|
|
29
34
|
})
|
|
30
35
|
})
|
|
@@ -32,57 +37,35 @@ const initializeGitRepository = (path) =>
|
|
|
32
37
|
/**
|
|
33
38
|
* init new yarn project
|
|
34
39
|
*/
|
|
35
|
-
const initializeYarn = (path) =>
|
|
40
|
+
const initializeYarn = (path, { yes } = {}) =>
|
|
36
41
|
new Promise((resolve, reject) => {
|
|
37
|
-
const
|
|
42
|
+
const params = ['init']
|
|
43
|
+
if (yes) params.push('-y')
|
|
44
|
+
|
|
45
|
+
const yarn = spawn('yarn', params, {
|
|
38
46
|
cwd: path,
|
|
39
47
|
stdio: [0, 1, 2]
|
|
40
48
|
})
|
|
41
49
|
yarn.on('close', (code) => {
|
|
42
50
|
if (code === 0) return resolve(code)
|
|
51
|
+
/* c8 ignore next */
|
|
43
52
|
reject(code)
|
|
44
53
|
})
|
|
45
54
|
})
|
|
46
55
|
|
|
47
56
|
/**
|
|
48
|
-
* install
|
|
49
|
-
*/
|
|
50
|
-
const installDevPackages = (appPath, skelPath) => {
|
|
51
|
-
const skelPack = readPackageUpSync({ cwd: skelPath })
|
|
52
|
-
const devDependencies = Object.entries(
|
|
53
|
-
skelPack.packageJson.devDependencies
|
|
54
|
-
).map(([key, val]) => `${key}@${val}`)
|
|
55
|
-
|
|
56
|
-
return new Promise((resolve, reject) => {
|
|
57
|
-
const yarn = spawn('yarn', ['add', ...devDependencies, '-D'], {
|
|
58
|
-
cwd: appPath
|
|
59
|
-
})
|
|
60
|
-
yarn.stdout.on('data', (data) => process.stdout.write(data))
|
|
61
|
-
yarn.stderr.on('data', (data) => process.stderr.write(data))
|
|
62
|
-
yarn.on('close', (code) => {
|
|
63
|
-
if (code === 0) return resolve(code)
|
|
64
|
-
reject(code)
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* install extra prod packages from skeleleton
|
|
57
|
+
* install packages
|
|
71
58
|
*/
|
|
72
|
-
const installPackages = (appPath
|
|
73
|
-
const skelPack = readPackageUpSync({ cwd: skelPath })
|
|
74
|
-
const dependencies = Object.entries(skelPack.packageJson.dependencies).map(
|
|
75
|
-
([key, val]) => `${key}@${val}`
|
|
76
|
-
)
|
|
77
|
-
|
|
59
|
+
const installPackages = (appPath) => {
|
|
78
60
|
return new Promise((resolve, reject) => {
|
|
79
|
-
const yarn = spawn('yarn', ['
|
|
61
|
+
const yarn = spawn('yarn', ['install'], {
|
|
80
62
|
cwd: appPath
|
|
81
63
|
})
|
|
82
64
|
yarn.stdout.on('data', (data) => process.stdout.write(data))
|
|
83
65
|
yarn.stderr.on('data', (data) => process.stderr.write(data))
|
|
84
66
|
yarn.on('close', (code) => {
|
|
85
67
|
if (code === 0) return resolve(code)
|
|
68
|
+
/* c8 ignore next */
|
|
86
69
|
reject(code)
|
|
87
70
|
})
|
|
88
71
|
})
|
|
@@ -102,6 +85,9 @@ const addPackageConfig = (path, skelPath) => {
|
|
|
102
85
|
pack.packageJson.scripts = skelPack.packageJson.scripts
|
|
103
86
|
pack.packageJson['lint-staged'] = skelPack.packageJson['lint-staged']
|
|
104
87
|
|
|
88
|
+
pack.packageJson.dependencies = skelPack.packageJson.dependencies
|
|
89
|
+
pack.packageJson.devDependencies = skelPack.packageJson.devDependencies
|
|
90
|
+
|
|
105
91
|
return writePackage(pack.path, pack.packageJson)
|
|
106
92
|
}
|
|
107
93
|
|
|
@@ -129,14 +115,10 @@ const copyEnv = (appPath, skelPath) => {
|
|
|
129
115
|
* define the command
|
|
130
116
|
*/
|
|
131
117
|
program
|
|
132
|
-
.version(
|
|
133
|
-
.arguments('<name>
|
|
118
|
+
.version(version)
|
|
119
|
+
.arguments('<name>')
|
|
120
|
+
.option('-y --yes')
|
|
134
121
|
.action(async (name, opt) => {
|
|
135
|
-
if (typeof name === 'undefined') {
|
|
136
|
-
console.error('please specify your new apps name...')
|
|
137
|
-
process.exit(1)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
122
|
/**
|
|
141
123
|
* the root directory of new project
|
|
142
124
|
*/
|
|
@@ -151,10 +133,9 @@ program
|
|
|
151
133
|
* setup new app
|
|
152
134
|
*/
|
|
153
135
|
await initializeGitRepository(root)
|
|
154
|
-
await initializeYarn(root)
|
|
155
|
-
await installDevPackages(root, skeleton)
|
|
156
|
-
await installPackages(root, skeleton)
|
|
136
|
+
await initializeYarn(root, opt)
|
|
157
137
|
await addPackageConfig(root, skeleton)
|
|
138
|
+
await installPackages(root)
|
|
158
139
|
await copySkeleton(root, skeleton)
|
|
159
140
|
await copyEnv(root, skeleton)
|
|
160
141
|
})
|
|
@@ -163,10 +144,3 @@ program
|
|
|
163
144
|
* read args
|
|
164
145
|
*/
|
|
165
146
|
program.parse(process.argv)
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* output help as default
|
|
169
|
-
*/
|
|
170
|
-
if (!process.argv.slice(2).length) {
|
|
171
|
-
program.help()
|
|
172
|
-
}
|
package/package.json
CHANGED
|
@@ -1,29 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uscreen.de/create-fastify-app",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "cli to create a new @uscreen.de/fastify-app",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"
|
|
7
|
+
"homepage": "https://github.com/uscreen/create-fastify-app",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/uscreen/create-fastify-app.git"
|
|
11
|
+
},
|
|
8
12
|
"author": "Marcus Spiegel <spiegel@uscreen.de>",
|
|
9
13
|
"license": "MIT",
|
|
10
14
|
"bin": {
|
|
11
15
|
"create-fastify-app": "./bin/cli.js"
|
|
12
16
|
},
|
|
13
17
|
"scripts": {
|
|
18
|
+
"test": "c8 tap",
|
|
19
|
+
"test:cov": "c8 --reporter=html --reporter=text tap",
|
|
20
|
+
"test:ci": "c8 --reporter=lcovonly tap",
|
|
14
21
|
"lint": "eslint --fix",
|
|
15
22
|
"prepare": "husky install"
|
|
16
23
|
},
|
|
17
24
|
"dependencies": {
|
|
18
|
-
"commander": "^
|
|
19
|
-
"fs-extra": "^
|
|
25
|
+
"commander": "^10.0.0",
|
|
26
|
+
"fs-extra": "^11.1.0",
|
|
20
27
|
"read-pkg-up": "^9.1.0",
|
|
21
28
|
"write-pkg": "^5.0.0"
|
|
22
29
|
},
|
|
23
30
|
"devDependencies": {
|
|
24
31
|
"@uscreen.de/eslint-config-prettystandard-node": "^0.2.10",
|
|
32
|
+
"c8": "^7.12.0",
|
|
25
33
|
"husky": ">=8.0.2",
|
|
26
|
-
"lint-staged": ">=13.0.3"
|
|
34
|
+
"lint-staged": ">=13.0.3",
|
|
35
|
+
"strip-ansi": "^7.0.1",
|
|
36
|
+
"tap": "^16.3.4"
|
|
27
37
|
},
|
|
28
38
|
"lint-staged": {
|
|
29
39
|
"*.js": "eslint --cache --fix"
|
package/skeleton/.nvmrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
18
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
indent_style = space
|
|
6
|
+
indent_size = 2
|
|
7
|
+
end_of_line = lf
|
|
8
|
+
insert_final_newline = true
|
|
9
|
+
trim_trailing_whitespace = true
|
|
10
|
+
|
|
11
|
+
[{Makefile,**.mk}]
|
|
12
|
+
# Use tabs for indentation (Makefiles require tabs)
|
|
13
|
+
indent_style = tab
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# image: node:lts-alpine
|
|
2
|
+
|
|
3
|
+
# cache:
|
|
4
|
+
# paths:
|
|
5
|
+
# - node_modules/
|
|
6
|
+
# - .yarn
|
|
7
|
+
|
|
8
|
+
# stages:
|
|
9
|
+
# - test
|
|
10
|
+
# - audit
|
|
11
|
+
|
|
12
|
+
# test:
|
|
13
|
+
# stage: test
|
|
14
|
+
# script:
|
|
15
|
+
# - npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
|
|
16
|
+
# - yarn install --pure-lockfile --cache-folder .yarn
|
|
17
|
+
# - yarn test:ci
|
|
18
|
+
# coverage: '/^Statements\s*:\s*([^%]+)/'
|
|
19
|
+
|
|
20
|
+
# audit:
|
|
21
|
+
# stage: audit
|
|
22
|
+
# only:
|
|
23
|
+
# - schedules
|
|
24
|
+
# script:
|
|
25
|
+
# - yarn audit
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
18
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# ${app-name}
|
|
2
|
+
|
|
3
|
+
> __TODO:__
|
|
4
|
+
> add a name & short description of this apps purpose
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
* `make start`: start app on local dev
|
|
9
|
+
* `make test`: test app
|
|
10
|
+
|
|
11
|
+
## Configure
|
|
12
|
+
|
|
13
|
+
Configuration is read by dotenv from `app/.env` file and validated _[optional modified]_ by `app/config.js`. Please add extra defaults if needed to `config.js`. Default values should __always__ refer to local dev setups.
|
|
14
|
+
|
|
15
|
+
> __Note:__
|
|
16
|
+
> the `.env` file should __never__ get pushed to repository. So adding secrets and credentials to `.env` can be considered a secure option bound to specific environments.
|
|
17
|
+
|
|
18
|
+
## Api
|
|
19
|
+
|
|
20
|
+
After starting your server you will find swagger documenation at [http://127.0.0.1:3000/api/docs/](http://127.0.0.1:3000/api/docs/) to explore web api requests interactively.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Roadmap
|
|
25
|
+
|
|
26
|
+
> TBD
|
|
27
|
+
|
|
28
|
+
## Changelog
|
|
29
|
+
|
|
30
|
+
### v0.0.0
|
|
31
|
+
|
|
32
|
+
- initially bootstrapped by `yarn create @uscreen.de/fastify-app`
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Credits
|
|
37
|
+
|
|
38
|
+
application [boilerplate](https://www.npmjs.com/package/@uscreen.de/fastify-app) provided by [u|screen](https://uscreen.de)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fastifyApp from '@uscreen.de/fastify-app'
|
|
2
|
+
import fp from 'fastify-plugin'
|
|
3
|
+
import schemas from './schemas.js'
|
|
4
|
+
|
|
5
|
+
export default fp((fastify, opts, next) => {
|
|
6
|
+
/**
|
|
7
|
+
* add schemas
|
|
8
|
+
*/
|
|
9
|
+
fastify.register(schemas)
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* register app
|
|
13
|
+
*/
|
|
14
|
+
fastify.register(fastifyApp, opts)
|
|
15
|
+
|
|
16
|
+
next()
|
|
17
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import envSchema from 'env-schema'
|
|
2
|
+
import CommonESM from '@uscreen.de/common-esm'
|
|
3
|
+
|
|
4
|
+
const { join } = new CommonESM(import.meta.url)
|
|
5
|
+
|
|
6
|
+
const schema = {
|
|
7
|
+
type: 'object',
|
|
8
|
+
properties: {
|
|
9
|
+
httpPort: { default: 3000 },
|
|
10
|
+
httpBind: { default: '127.0.0.1' },
|
|
11
|
+
prefix: { default: '/api' },
|
|
12
|
+
logEnabled: { default: true },
|
|
13
|
+
logLevel: { default: 'info' }
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const config = envSchema({
|
|
18
|
+
schema: schema,
|
|
19
|
+
dotenv: true
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
config.autoloads = [join('plugins'), join('services')]
|
|
23
|
+
|
|
24
|
+
config.swagger = {
|
|
25
|
+
routePrefix: `${config.prefix}/docs`,
|
|
26
|
+
exposeRoute: true,
|
|
27
|
+
addModels: true
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
config.health = {
|
|
31
|
+
exposeStatusRoute: `${config.prefix}/health`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default config
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import fp from 'fastify-plugin'
|
|
2
|
+
import S from 'fluent-json-schema'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Usage of the Globaly Shared Schema feature
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export default fp((fastify, opts, next) => {
|
|
9
|
+
const addSchema = (schema) => {
|
|
10
|
+
fastify.addSchema(schema)
|
|
11
|
+
return schema
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* add generic schemas
|
|
16
|
+
*/
|
|
17
|
+
const noop = addSchema(S.object().id('noop').prop('noop'))
|
|
18
|
+
|
|
19
|
+
const plugin = addSchema(S.object().id('plugin').prop('plugin'))
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* combine and extend schemas
|
|
23
|
+
*/
|
|
24
|
+
addSchema(
|
|
25
|
+
S.object()
|
|
26
|
+
.id('noopNplugin')
|
|
27
|
+
.required(['noop'])
|
|
28
|
+
// .prop('property') // --> strip it
|
|
29
|
+
.extend(noop)
|
|
30
|
+
.extend(plugin)
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
next()
|
|
34
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import fastify from 'fastify'
|
|
2
|
+
import { options } from '@uscreen.de/fastify-app'
|
|
3
|
+
import config from './config.js'
|
|
4
|
+
import app from './app.js'
|
|
5
|
+
|
|
6
|
+
const server = fastify(options(config))
|
|
7
|
+
|
|
8
|
+
server.register(app, config)
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* post-treatment
|
|
12
|
+
*/
|
|
13
|
+
server.ready((err) => {
|
|
14
|
+
if (err) throw err
|
|
15
|
+
server.log.debug(
|
|
16
|
+
'server ready, routes are set:\n' +
|
|
17
|
+
server.printRoutes({ commonPrefix: false })
|
|
18
|
+
)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* graceful shutdown (closing handles, etc.)
|
|
23
|
+
*/
|
|
24
|
+
const shutdown = async () => {
|
|
25
|
+
server.log.info(
|
|
26
|
+
`application shutting down. (${server.app.name} ${server.app.version})`
|
|
27
|
+
)
|
|
28
|
+
await server.close()
|
|
29
|
+
process.exit()
|
|
30
|
+
}
|
|
31
|
+
process.on('SIGINT', shutdown)
|
|
32
|
+
process.on('SIGTERM', shutdown)
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* start http server
|
|
36
|
+
*/
|
|
37
|
+
server.listen({ port: config.httpPort, host: config.httpBind })
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default (fastify, opts, next) => {
|
|
2
|
+
fastify.get(
|
|
3
|
+
'/noop',
|
|
4
|
+
{
|
|
5
|
+
schema: {
|
|
6
|
+
response: {
|
|
7
|
+
200: { $ref: 'noopNplugin#' } // fastest and json-schema spec compatiple way, or use 'fastify.getSchema()'
|
|
8
|
+
// 200: fastify.getSchema('noopNplugin')
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
async (req, res) => {
|
|
13
|
+
return {
|
|
14
|
+
noop: 'Hello world',
|
|
15
|
+
plugin: fastify.noop(),
|
|
16
|
+
property: 'should be stripped from response'
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
next()
|
|
22
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "new-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "app/server.js",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Martin Herting",
|
|
7
|
+
"email": "herting@uscreen.de"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"type": "module",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "nodemon",
|
|
13
|
+
"lint": "eslint --fix",
|
|
14
|
+
"test": "c8 tap",
|
|
15
|
+
"test:cov": "c8 --reporter=html --reporter=text tap",
|
|
16
|
+
"test:ci": "tap",
|
|
17
|
+
"prepare": "husky install"
|
|
18
|
+
},
|
|
19
|
+
"lint-staged": {
|
|
20
|
+
"*.js": "eslint --cache --fix"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@uscreen.de/common-esm": "^1.0.0",
|
|
24
|
+
"@uscreen.de/fastify-app": "^1.0.0-0",
|
|
25
|
+
"env-schema": "^5.1.1",
|
|
26
|
+
"fastify": "^4.10.2",
|
|
27
|
+
"fastify-plugin": "^4.3.0",
|
|
28
|
+
"fluent-json-schema": "^4.0.0",
|
|
29
|
+
"pino-pretty": "^9.1.1"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@uscreen.de/eslint-config-prettystandard-node": "^0.2.8",
|
|
33
|
+
"c8": "^7.12.0",
|
|
34
|
+
"husky": ">=6",
|
|
35
|
+
"lint-staged": ">=10",
|
|
36
|
+
"nodemon": "^2.0.20",
|
|
37
|
+
"prettier": "^2.8.0",
|
|
38
|
+
"tap": "^16.3.2"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import tap from 'tap'
|
|
2
|
+
import { build } from '../helper.js'
|
|
3
|
+
|
|
4
|
+
tap.test('Test Setup', (t) => {
|
|
5
|
+
t.equal(true, true, 'Tests and assertions should work')
|
|
6
|
+
t.end()
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
tap.test('Healthcheck', async (t) => {
|
|
10
|
+
const fastify = await build(t)
|
|
11
|
+
const { prefix } = fastify.config
|
|
12
|
+
|
|
13
|
+
t.test('a valid GET Request', (t) => {
|
|
14
|
+
fastify.inject(
|
|
15
|
+
{
|
|
16
|
+
method: 'GET',
|
|
17
|
+
url: `${prefix}/health`
|
|
18
|
+
},
|
|
19
|
+
(e, response) => {
|
|
20
|
+
t.error(e)
|
|
21
|
+
t.same(response.statusCode, 200, 'response ok')
|
|
22
|
+
t.same(JSON.parse(response.body), { status: 'ok' }, 'payload ok')
|
|
23
|
+
t.end()
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
tap.test('Noop Service', async (t) => {
|
|
30
|
+
const fastify = await build(t)
|
|
31
|
+
const { prefix } = fastify.config
|
|
32
|
+
|
|
33
|
+
t.test('a valid GET Request', (t) => {
|
|
34
|
+
fastify.inject(
|
|
35
|
+
{
|
|
36
|
+
method: 'GET',
|
|
37
|
+
url: `${prefix}/noop`
|
|
38
|
+
},
|
|
39
|
+
(e, response) => {
|
|
40
|
+
t.error(e)
|
|
41
|
+
t.same(response.statusCode, 200, 'response ok')
|
|
42
|
+
t.same(
|
|
43
|
+
JSON.parse(response.body),
|
|
44
|
+
{
|
|
45
|
+
noop: 'Hello world',
|
|
46
|
+
plugin: 'Hello Universe'
|
|
47
|
+
},
|
|
48
|
+
'payload ok'
|
|
49
|
+
)
|
|
50
|
+
t.end()
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// This file contains code that we reuse
|
|
2
|
+
// between our tests.
|
|
3
|
+
|
|
4
|
+
import Fastify from 'fastify'
|
|
5
|
+
import fp from 'fastify-plugin'
|
|
6
|
+
|
|
7
|
+
// setup to import YOUR app
|
|
8
|
+
import App from '../app/app.js'
|
|
9
|
+
import Config from '../app/config.js'
|
|
10
|
+
|
|
11
|
+
// automatically build and tear down our instance
|
|
12
|
+
export const build = async (t, ConfigOverwrite = {}) => {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
const app = Fastify()
|
|
15
|
+
|
|
16
|
+
// setup to register YOUR app
|
|
17
|
+
app.register(fp(App), { ...Config, ...ConfigOverwrite })
|
|
18
|
+
|
|
19
|
+
// tear down our app after we are done
|
|
20
|
+
t.teardown(app.close.bind(app))
|
|
21
|
+
|
|
22
|
+
app.ready((err) => {
|
|
23
|
+
if (err) throw err
|
|
24
|
+
resolve(app)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
package/test/cli.test.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import tap from 'tap'
|
|
2
|
+
import fs from 'fs-extra'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { createRequire } from 'module'
|
|
5
|
+
import stripAnsi from 'strip-ansi'
|
|
6
|
+
import { before, teardown, cli, cwd } from './setup.js'
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url)
|
|
9
|
+
const { version } = require('../package.json')
|
|
10
|
+
|
|
11
|
+
tap.before(before)
|
|
12
|
+
tap.teardown(teardown)
|
|
13
|
+
|
|
14
|
+
tap.test('$ cli', async (t) => {
|
|
15
|
+
const result = await cli([])
|
|
16
|
+
t.equal(
|
|
17
|
+
true,
|
|
18
|
+
result.stderr.startsWith("error: missing required argument 'name'"),
|
|
19
|
+
'Should print error message'
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
t.end()
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
tap.test('$ cli -V', async (t) => {
|
|
26
|
+
const result = await cli(['--version'])
|
|
27
|
+
t.equal(
|
|
28
|
+
true,
|
|
29
|
+
result.stdout.startsWith(version),
|
|
30
|
+
'Should show correct version'
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
t.end()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
tap.test('$ cli new-app -y', async (t) => {
|
|
37
|
+
const result = await cli(['new-app', '-y'])
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* check output
|
|
41
|
+
*/
|
|
42
|
+
t.equal(0, result.code, 'Should succeed')
|
|
43
|
+
|
|
44
|
+
t.test('Check output', (t) => {
|
|
45
|
+
const expectedOut = [
|
|
46
|
+
`Initialized empty Git repository in ${path.resolve(
|
|
47
|
+
cwd,
|
|
48
|
+
'new-app',
|
|
49
|
+
'.git'
|
|
50
|
+
)}`,
|
|
51
|
+
'success Saved package.json',
|
|
52
|
+
'[1/4] Resolving packages...',
|
|
53
|
+
'[2/4] Fetching packages...',
|
|
54
|
+
'[3/4] Linking dependencies...',
|
|
55
|
+
'[4/4] Building fresh packages...',
|
|
56
|
+
'success Saved lockfile.',
|
|
57
|
+
'husky - Git hooks installed'
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
const stdout = stripAnsi(result.stdout)
|
|
61
|
+
|
|
62
|
+
for (const e of expectedOut) {
|
|
63
|
+
t.equal(true, stdout.includes(e), `"${e.substring(0, 36)}"`)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
t.end()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* check files
|
|
71
|
+
*/
|
|
72
|
+
t.test('Check files', (t) => {
|
|
73
|
+
const appPath = path.resolve(cwd, 'new-app')
|
|
74
|
+
|
|
75
|
+
t.equal(
|
|
76
|
+
true,
|
|
77
|
+
fs.existsSync(path.resolve(appPath, 'package.json')),
|
|
78
|
+
'package.json was created'
|
|
79
|
+
)
|
|
80
|
+
t.equal(
|
|
81
|
+
true,
|
|
82
|
+
fs.existsSync(path.resolve(appPath, 'README.md')),
|
|
83
|
+
'skeleton was copied'
|
|
84
|
+
)
|
|
85
|
+
t.equal(
|
|
86
|
+
true,
|
|
87
|
+
fs.existsSync(path.resolve(appPath, 'yarn.lock')),
|
|
88
|
+
'Packages were installed'
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
const pack = JSON.parse(
|
|
92
|
+
fs.readFileSync(path.resolve(appPath, 'package.json'), {
|
|
93
|
+
encoding: 'utf-8'
|
|
94
|
+
})
|
|
95
|
+
)
|
|
96
|
+
t.equal(
|
|
97
|
+
true,
|
|
98
|
+
pack.name !== 'new-fastify-app',
|
|
99
|
+
'package.json was not just copied from skeleton'
|
|
100
|
+
)
|
|
101
|
+
t.equal(
|
|
102
|
+
true,
|
|
103
|
+
pack.main === 'app/server.js',
|
|
104
|
+
'package.json was correctly enriched with data'
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
t.end()
|
|
108
|
+
})
|
|
109
|
+
})
|
package/test/setup.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import fs from 'fs-extra'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { exec } from 'child_process'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
|
|
8
|
+
export const cwd = path.resolve(__dirname, './_arena/')
|
|
9
|
+
|
|
10
|
+
export const cli = (args) => {
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
exec(
|
|
13
|
+
`node ${path.resolve(__dirname, '../bin/cli.js')} ${args.join(' ')}`,
|
|
14
|
+
{ cwd },
|
|
15
|
+
(error, stdout, stderr) => {
|
|
16
|
+
resolve({
|
|
17
|
+
code: error && error.code ? error.code : 0,
|
|
18
|
+
error,
|
|
19
|
+
stdout,
|
|
20
|
+
stderr
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const before = () => {
|
|
28
|
+
fs.ensureDirSync(cwd)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const teardown = () => {
|
|
32
|
+
fs.removeSync(cwd)
|
|
33
|
+
}
|