@uscreen.de/create-fastify-app 0.0.0 → 0.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.
@@ -0,0 +1,15 @@
1
+ # image: node:10
2
+
3
+ # cache:
4
+ # paths:
5
+ # - node_modules/
6
+
7
+ # stages:
8
+ # - test
9
+
10
+ # test:
11
+ # stage: test
12
+ # script:
13
+ # - yarn install
14
+ # - yarn test:ci
15
+ # coverage: '/^Statements\s*:\s*([^%]+)/'
package/bin/cli.js CHANGED
@@ -1,23 +1,162 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ const path = require('path')
3
4
  const cli = require('commander')
5
+ const readPkgUp = require('read-pkg-up')
6
+ const writePackage = require('write-pkg')
7
+ const fs = require('fs-extra')
4
8
 
5
- let nameValue
6
- let optValue
9
+ const { spawn } = require('child_process')
7
10
 
11
+ let root
12
+ let skeleton
13
+
14
+ /**
15
+ * init new git
16
+ */
17
+ const initializeGitRepository = path =>
18
+ new Promise((resolve, reject) => {
19
+ const git = spawn('git', ['init', path])
20
+ git.stdout.on('data', data => process.stdout.write(data))
21
+ git.stderr.on('data', data => process.stderr.write(data))
22
+ git.on('close', code => {
23
+ if (code === 0) return resolve(code)
24
+ reject(code)
25
+ })
26
+ })
27
+
28
+ /**
29
+ * init new yarn project
30
+ */
31
+ const initializeYarn = path =>
32
+ new Promise((resolve, reject) => {
33
+ const yarn = spawn('yarn', ['init'], {
34
+ cwd: path,
35
+ stdio: [0, 1, 2]
36
+ })
37
+ yarn.on('close', code => {
38
+ if (code === 0) return resolve(code)
39
+ reject(code)
40
+ })
41
+ })
42
+
43
+ /**
44
+ * install extra dev packages from skeleleton
45
+ */
46
+ const installDevPackages = (appPath, skelPath) => {
47
+ const skelPack = readPkgUp.sync({ cwd: skelPath })
48
+ const devDependencies = Object.keys(skelPack.packageJson.devDependencies)
49
+ return new Promise((resolve, reject) => {
50
+ const yarn = spawn('yarn', ['add', ...devDependencies, '-D'], {
51
+ cwd: appPath
52
+ })
53
+ yarn.stdout.on('data', data => process.stdout.write(data))
54
+ yarn.stderr.on('data', data => process.stderr.write(data))
55
+ yarn.on('close', code => {
56
+ if (code === 0) return resolve(code)
57
+ reject(code)
58
+ })
59
+ })
60
+ }
61
+
62
+ /**
63
+ * install extra prod packages from skeleleton
64
+ */
65
+ const installPackages = (appPath, skelPath) => {
66
+ const skelPack = readPkgUp.sync({ cwd: skelPath })
67
+ const dependencies = Object.keys(skelPack.packageJson.dependencies)
68
+ return new Promise((resolve, reject) => {
69
+ const yarn = spawn('yarn', ['add', ...dependencies], {
70
+ cwd: appPath
71
+ })
72
+ yarn.stdout.on('data', data => process.stdout.write(data))
73
+ yarn.stderr.on('data', data => process.stderr.write(data))
74
+ yarn.on('close', code => {
75
+ if (code === 0) return resolve(code)
76
+ reject(code)
77
+ })
78
+ })
79
+ }
80
+
81
+ /**
82
+ * configure package.json to use linting, testing, stuff
83
+ */
84
+ const addPackageConfig = (path, skelPath) => {
85
+ const skelPack = readPkgUp.sync({ cwd: skelPath })
86
+ const pack = readPkgUp.sync({ cwd: path })
87
+ delete pack.packageJson._id
88
+ delete pack.packageJson.readme
89
+
90
+ pack.packageJson.main = skelPack.packageJson.main
91
+
92
+ pack.packageJson.scripts = Object.assign(pack.packageJson.scripts || {}, {
93
+ start: 'pm2 start pm2-dev.config.js',
94
+ stop: 'pm2 delete pm2-dev.config.js',
95
+ logs: `pm2 logs ${pack.packageJson.name} --raw | pino-pretty -t`,
96
+ lint: "eslint '**/*.js' --fix",
97
+ test: 'tap test/**/*.test.js',
98
+ 'test:cov': 'tap --coverage-report=html test/**/*.test.js',
99
+ 'test:ci': 'tap --coverage-report=text-summary test/**/*.test.js',
100
+ deploy: 'pm2 deploy pm2.config.js',
101
+ postdeploy: 'pm2 reload pm2.config.js'
102
+ })
103
+ pack.packageJson.gitHooks = {
104
+ 'pre-commit': 'lint-staged'
105
+ }
106
+ pack.packageJson['lint-staged'] = {
107
+ '*.{js}': ['eslint --fix', 'git add']
108
+ }
109
+ return writePackage(pack.path, pack.packageJson)
110
+ }
111
+
112
+ /**
113
+ * copy app skeleton to destination
114
+ */
115
+ const copySkeleton = (appPath, skelPath) => {
116
+ return fs.copy(skelPath, appPath, { overwrite: false })
117
+ }
118
+
119
+ /**
120
+ * define the command
121
+ */
8
122
  cli
9
123
  .version('0.1.0')
10
124
  .arguments('<name> [opt]')
11
- .action(function(name, opt) {
12
- nameValue = name
13
- optValue = opt
125
+ .action(async (name, opt) => {
126
+ if (typeof name === 'undefined') {
127
+ console.error('please specify your new apps name...')
128
+ process.exit(1)
129
+ }
130
+
131
+ /**
132
+ * the root directory of new project
133
+ */
134
+ root = path.resolve(process.cwd(), name)
135
+
136
+ /**
137
+ * the root directory of chosen skeleton
138
+ */
139
+ skeleton = path.join(__dirname, '..', 'skeleton')
140
+
141
+ /**
142
+ * setup new app
143
+ */
144
+ await initializeGitRepository(root)
145
+ await initializeYarn(root)
146
+ await installDevPackages(root, skeleton)
147
+ await installPackages(root, skeleton)
148
+ await addPackageConfig(root, skeleton)
149
+ await copySkeleton(root, skeleton)
14
150
  })
15
151
 
152
+ /**
153
+ * read args
154
+ */
16
155
  cli.parse(process.argv)
17
156
 
18
- if (typeof nameValue === 'undefined') {
19
- console.error('please specify your new apps name...')
20
- process.exit(1)
157
+ /**
158
+ * output help as default
159
+ */
160
+ if (!process.argv.slice(2).length) {
161
+ cli.help()
21
162
  }
22
- console.log('name:', nameValue)
23
- console.log('opt:', optValue)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uscreen.de/create-fastify-app",
3
- "version": "0.0.0",
3
+ "version": "0.1.1",
4
4
  "description": "cli to create a new @uscreen.de/fastify-app",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -25,7 +25,10 @@
25
25
  ]
26
26
  },
27
27
  "dependencies": {
28
- "commander": "^3.0.2"
28
+ "commander": "^3.0.2",
29
+ "fs-extra": "^8.1.0",
30
+ "read-pkg-up": "^7.0.0",
31
+ "write-pkg": "^4.0.0"
29
32
  },
30
33
  "devDependencies": {
31
34
  "eslint": "^6.5.1",
@@ -0,0 +1,4 @@
1
+ # @see ./app/config.js for defaults and options
2
+
3
+ logLevel = debug
4
+
@@ -0,0 +1,4 @@
1
+ # @see https://direnv.net/ and https://github.com/direnv/direnv/wiki/Node for docs
2
+ set -e
3
+ use node
4
+ layout node
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ root: true,
3
+ env: {
4
+ node: true
5
+ },
6
+ extends: ['standard', 'plugin:prettier/recommended'],
7
+ rules: {
8
+ 'generator-star-spacing': 'off',
9
+ 'space-before-function-paren': 'off',
10
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
11
+ }
12
+ }
@@ -0,0 +1,15 @@
1
+ # image: node:10
2
+
3
+ # cache:
4
+ # paths:
5
+ # - node_modules/
6
+
7
+ # stages:
8
+ # - test
9
+
10
+ # test:
11
+ # stage: test
12
+ # script:
13
+ # - yarn install
14
+ # - yarn test:ci
15
+ # coverage: '/^Statements\s*:\s*([^%]+)/'
@@ -0,0 +1 @@
1
+ 10
@@ -0,0 +1,4 @@
1
+ semi: false
2
+ singleQuote: true
3
+ trailingComma: none
4
+ bracketSpacing: true
@@ -0,0 +1,3 @@
1
+ {
2
+ "reporter": "spec"
3
+ }
@@ -0,0 +1,29 @@
1
+ start:
2
+ yarn
3
+ yarn start
4
+
5
+ stop:
6
+ yarn stop
7
+
8
+ logs:
9
+ yarn logs
10
+
11
+ test:
12
+ yarn test
13
+
14
+ test.coverage:
15
+ yarn test:cov
16
+
17
+ deploy:
18
+ yarn deploy stage
19
+
20
+ deploy.setup:
21
+ yarn deploy stage setup
22
+
23
+ live.deploy:
24
+ yarn deploy live
25
+
26
+ live.deploy.setup:
27
+ yarn deploy live setup
28
+
29
+ .PHONY: test
@@ -0,0 +1,19 @@
1
+ 'use strict'
2
+
3
+ const fastifyApp = require('@uscreen.de/fastify-app')
4
+ const fp = require('fastify-plugin')
5
+ const schemas = require('./schemas')
6
+
7
+ module.exports = fp(async (fastify, opts, next) => {
8
+ /**
9
+ * add schemas
10
+ */
11
+ fastify.register(schemas)
12
+
13
+ /**
14
+ * register app
15
+ */
16
+ fastify.register(fastifyApp, opts)
17
+
18
+ next()
19
+ })
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ const path = require('path')
4
+ const envSchema = require('env-schema')
5
+
6
+ const schema = {
7
+ type: 'object',
8
+ properties: {
9
+ httpPort: {
10
+ default: 3000
11
+ },
12
+ httpBind: {
13
+ default: '127.0.0.1'
14
+ },
15
+ prefix: {
16
+ default: '/api'
17
+ },
18
+ logEnabled: {
19
+ default: true
20
+ },
21
+ logLevel: {
22
+ default: 'info'
23
+ }
24
+ }
25
+ }
26
+
27
+ const config = envSchema({
28
+ schema: schema,
29
+ dotenv: true
30
+ })
31
+
32
+ config.autoloads = [
33
+ path.join(__dirname, 'plugins'),
34
+ path.join(__dirname, 'services')
35
+ ]
36
+
37
+ config.swagger = {
38
+ routePrefix: '/api/docs',
39
+ exposeRoute: true,
40
+ addModels: true
41
+ }
42
+
43
+ config.healthCheck = {
44
+ exposeStatusRoute: '/api/health'
45
+ }
46
+
47
+ module.exports = config
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ const fp = require('fastify-plugin')
4
+
5
+ module.exports = fp(async (fastify, opts, next) => {
6
+ fastify.decorate('noop', () => {
7
+ return 'Hello Universe'
8
+ })
9
+
10
+ next()
11
+ })
@@ -0,0 +1,41 @@
1
+ 'use strict'
2
+
3
+ const fp = require('fastify-plugin')
4
+
5
+ /**
6
+ * Usage of the Globaly Shared Schema feature
7
+ */
8
+
9
+ module.exports = fp(async (fastify, opts, next) => {
10
+ fastify.addSchema({
11
+ $id: 'http200',
12
+ type: 'object',
13
+ properties: {
14
+ statusCode: {
15
+ type: 'integer',
16
+ example: 200
17
+ }
18
+ }
19
+ })
20
+
21
+ fastify.addSchema({
22
+ $id: 'http404',
23
+ type: 'object',
24
+ properties: {
25
+ statusCode: {
26
+ type: 'integer',
27
+ example: 404
28
+ },
29
+ error: {
30
+ type: 'string',
31
+ example: 'Not Found'
32
+ },
33
+ message: {
34
+ type: 'string',
35
+ example: 'Not Found'
36
+ }
37
+ }
38
+ })
39
+
40
+ next()
41
+ })
@@ -0,0 +1,28 @@
1
+ 'use strict'
2
+
3
+ const fastify = require('fastify')
4
+ const config = require('./config')
5
+ const myapp = require('./app')
6
+
7
+ const app = fastify({
8
+ logger: config.logEnabled
9
+ ? {
10
+ level: config.logLevel
11
+ }
12
+ : false
13
+ })
14
+
15
+ app.register(myapp, config)
16
+
17
+ /**
18
+ * post-treatment
19
+ */
20
+ app.ready(err => {
21
+ if (err) throw err
22
+ app.log.debug('Application ready, routes are set:\n' + app.printRoutes())
23
+ })
24
+
25
+ /**
26
+ * start http server
27
+ */
28
+ app.listen(config.httpPort, config.httpBind)
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ module.exports = async fastify => {
4
+ fastify.get('/noop', async (req, res) => {
5
+ return { noop: 'Hello world', plugin: fastify.noop() }
6
+ })
7
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "new-fastify-app",
3
+ "version": "0.0.0",
4
+ "main": "app/server.js",
5
+ "license": "MIT",
6
+ "dependencies": {
7
+ "@uscreen.de/fastify-app": "^0.2.9",
8
+ "env-schema": "^1.0.0",
9
+ "fastify": "^2.9.0",
10
+ "fastify-plugin": "^1.6.0"
11
+ },
12
+ "devDependencies": {
13
+ "eslint": "^6.5.1",
14
+ "eslint-config-prettier": "^6.3.0",
15
+ "eslint-config-standard": "^14.1.0",
16
+ "eslint-plugin-import": "^2.18.2",
17
+ "eslint-plugin-node": "^10.0.0",
18
+ "eslint-plugin-prettier": "^3.1.1",
19
+ "eslint-plugin-promise": "^4.2.1",
20
+ "eslint-plugin-standard": "^4.0.1",
21
+ "lint-staged": "^9.4.1",
22
+ "pm2": "^3.5.1",
23
+ "prettier": "^1.18.2",
24
+ "tap": "^14.6.9",
25
+ "yorkie": "^2.0.0"
26
+ },
27
+ "scripts": {
28
+ "start": "pm2 start pm2-dev.config.js",
29
+ "stop": "pm2 delete pm2-dev.config.js",
30
+ "logs": "pm2 logs new-fastify-app --raw | pino-pretty -t",
31
+ "lint": "eslint '**/*.js' --fix",
32
+ "test": "tap test/**/*.test.js",
33
+ "test:cov": "tap --coverage-report=html test/**/*.test.js",
34
+ "test:ci": "tap --coverage-report=text-summary test/**/*.test.js",
35
+ "deploy": "pm2 deploy pm2.config.js",
36
+ "postdeploy": "pm2 reload pm2.config.js"
37
+ },
38
+ "gitHooks": {
39
+ "pre-commit": "lint-staged"
40
+ },
41
+ "lint-staged": {
42
+ "*.{js}": [
43
+ "eslint --fix",
44
+ "git add"
45
+ ]
46
+ }
47
+ }
@@ -0,0 +1,16 @@
1
+ const { name, main } = require('./package.json')
2
+
3
+ module.exports = {
4
+ apps: [
5
+ {
6
+ name,
7
+ script: main,
8
+ merge_logs: true,
9
+ watch: ['app'],
10
+ ignore_watch: ['.git', 'app/*.pid'],
11
+ env: {
12
+ NODE_ENV: 'development'
13
+ }
14
+ }
15
+ ]
16
+ }
@@ -0,0 +1,28 @@
1
+ const { name, main, repository } = require('./package.json')
2
+
3
+ module.exports = {
4
+ apps: [
5
+ {
6
+ name,
7
+ script: main,
8
+ merge_logs: true,
9
+ ignore_watch: ['.git', 'app/*.pid'],
10
+ env: {
11
+ NODE_ENV: 'production'
12
+ }
13
+ }
14
+ ],
15
+ deploy: {
16
+ stage: {
17
+ user: 'user',
18
+ host: 'server-stage.example.com',
19
+ ref: 'origin/master',
20
+ repo: repository,
21
+ path: `/home/user/${name}`,
22
+ 'pre-setup': 'yarn add pm2 pino-pretty;',
23
+ 'post-setup':
24
+ 'cp ./.env.example ../shared/.env; ln -s ../shared/.env ./.env',
25
+ 'post-deploy': 'yarn install --production; yarn postdeploy'
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ 'use strict'
2
+
3
+ // This file contains code that we reuse
4
+ // between our tests.
5
+
6
+ const Fastify = require('fastify')
7
+ const fp = require('fastify-plugin')
8
+
9
+ // setup to require YOUR app
10
+ const App = require('../app/app')
11
+ const Config = require('../app/config')
12
+
13
+ // automatically build and tear down our instance
14
+ function build(t, ConfigOverwrite = {}) {
15
+ const app = Fastify()
16
+
17
+ // setup to register YOUR app
18
+ app.register(fp(App), { ...Config, ...ConfigOverwrite })
19
+
20
+ // tear down our app after we are done
21
+ t.tearDown(app.close.bind(app))
22
+
23
+ return app
24
+ }
25
+
26
+ module.exports = {
27
+ build
28
+ }
@@ -0,0 +1,54 @@
1
+ const tap = require('tap')
2
+ const { build } = require('./helper')
3
+
4
+ tap.test('Test Setup', t => {
5
+ t.strictEqual(true, true, 'Tests and assertions should work')
6
+ t.end()
7
+ })
8
+
9
+ tap.test('Healthcheck', async t => {
10
+ const fastify = build(t)
11
+ await fastify.ready()
12
+
13
+ t.test('a valid GET Request', t => {
14
+ fastify.inject(
15
+ {
16
+ method: 'GET',
17
+ url: '/api/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 = build(t)
31
+ await fastify.ready()
32
+
33
+ t.test('a valid GET Request', t => {
34
+ fastify.inject(
35
+ {
36
+ method: 'GET',
37
+ url: '/api/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
+ })