@lenne.tech/cli 0.0.79 → 0.0.82
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/build/commands/deployment/create.js +118 -0
- package/build/commands/deployment/deployment.js +25 -0
- package/build/commands/server/module.js +67 -5
- package/build/extensions/server.js +234 -0
- package/build/interfaces/ServerProps.interface.js +3 -0
- package/build/templates/deployment/.github/workflows/pre-release.yml.ejs +41 -0
- package/build/templates/deployment/.github/workflows/release.yml.ejs +41 -0
- package/build/templates/deployment/.gitlab-ci.yml.ejs +187 -0
- package/build/templates/deployment/Dockerfile.app.ejs +13 -0
- package/build/templates/deployment/Dockerfile.ejs +18 -0
- package/build/templates/deployment/docker-compose.develop.yml.ejs +99 -0
- package/build/templates/deployment/docker-compose.prod.yml.ejs +92 -0
- package/build/templates/deployment/docker-compose.test.yml.ejs +98 -0
- package/build/templates/deployment/scripts/build-push.sh.ejs +20 -0
- package/build/templates/deployment/scripts/deploy.sh.ejs +7 -0
- package/build/templates/nest-server-module/inputs/template-create.input.ts.ejs +5 -8
- package/build/templates/nest-server-module/inputs/template.input.ts.ejs +3 -9
- package/build/templates/nest-server-module/template.model.ts.ejs +4 -21
- package/build/templates/nest-server-module/template.resolver.ts.ejs +2 -1
- package/package.json +5 -5
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
image: node:18-alpine
|
|
2
|
+
|
|
3
|
+
stages:
|
|
4
|
+
- install_dependencies
|
|
5
|
+
# - version_number
|
|
6
|
+
- build
|
|
7
|
+
- package
|
|
8
|
+
- deploy
|
|
9
|
+
|
|
10
|
+
variables:
|
|
11
|
+
APP_URL_PROD: <%= props.url %>
|
|
12
|
+
APP_URL_TEST: test.<%= props.url %>
|
|
13
|
+
STACK_NAME: $CI_PROJECT_NAME
|
|
14
|
+
FILE_NAME_PROD: docker-compose.prod.yml
|
|
15
|
+
FILE_NAME_TEST: docker-compose.test.yml
|
|
16
|
+
CI_NAME: 'gitlab'
|
|
17
|
+
CI_EMAIL: 'gitlab-ci@example.com'
|
|
18
|
+
|
|
19
|
+
install_dependencies:
|
|
20
|
+
stage: install_dependencies
|
|
21
|
+
cache:
|
|
22
|
+
key: $CI_PROJECT_DIR
|
|
23
|
+
paths:
|
|
24
|
+
- node_modules/
|
|
25
|
+
policy: push
|
|
26
|
+
script:
|
|
27
|
+
- npm ci
|
|
28
|
+
only:
|
|
29
|
+
refs:
|
|
30
|
+
- develop
|
|
31
|
+
- test
|
|
32
|
+
- release
|
|
33
|
+
- preview
|
|
34
|
+
- main
|
|
35
|
+
changes:
|
|
36
|
+
- package-lock.json
|
|
37
|
+
|
|
38
|
+
build_review:
|
|
39
|
+
stage: build
|
|
40
|
+
cache:
|
|
41
|
+
key: $CI_PROJECT_DIR
|
|
42
|
+
paths:
|
|
43
|
+
- node_modules/
|
|
44
|
+
policy: pull
|
|
45
|
+
artifacts:
|
|
46
|
+
paths:
|
|
47
|
+
- projects/api/dist/
|
|
48
|
+
- projects/app/dist/
|
|
49
|
+
expire_in: 5 minutes
|
|
50
|
+
script:
|
|
51
|
+
- npm run init
|
|
52
|
+
- npm run build
|
|
53
|
+
rules:
|
|
54
|
+
- if: $CI_MERGE_REQUEST_ID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "test" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "release" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "preview" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME != "main"
|
|
55
|
+
|
|
56
|
+
build:prod:
|
|
57
|
+
stage: build
|
|
58
|
+
cache:
|
|
59
|
+
key: $CI_PROJECT_DIR
|
|
60
|
+
paths:
|
|
61
|
+
- node_modules/
|
|
62
|
+
policy: pull
|
|
63
|
+
artifacts:
|
|
64
|
+
paths:
|
|
65
|
+
- projects/api/dist/
|
|
66
|
+
- projects/app/dist/
|
|
67
|
+
expire_in: 5 minutes
|
|
68
|
+
script:
|
|
69
|
+
- npm run init
|
|
70
|
+
- npm run build
|
|
71
|
+
only:
|
|
72
|
+
- main
|
|
73
|
+
|
|
74
|
+
build:test:
|
|
75
|
+
stage: build
|
|
76
|
+
image: tarampampam/node:16-alpine
|
|
77
|
+
cache:
|
|
78
|
+
key: $CI_PROJECT_DIR
|
|
79
|
+
paths:
|
|
80
|
+
- node_modules/
|
|
81
|
+
policy: pull
|
|
82
|
+
artifacts:
|
|
83
|
+
paths:
|
|
84
|
+
- projects/api/dist/
|
|
85
|
+
- projects/app/dist/
|
|
86
|
+
expire_in: 5 minutes
|
|
87
|
+
script:
|
|
88
|
+
- git config --global user.email $CI_EMAIL
|
|
89
|
+
- git config --global user.name $CI_NAME
|
|
90
|
+
- git config http.sslVerify "false"
|
|
91
|
+
- git config receive.advertisePushOptions true
|
|
92
|
+
- git fetch
|
|
93
|
+
- git pull https://${CI_USER}:${CI_ACCESS_TOKEN}@gitlab.lenne.tech/products/akademie/master-minds.git test:test
|
|
94
|
+
- npm run init
|
|
95
|
+
- npm run build:test
|
|
96
|
+
only:
|
|
97
|
+
- test
|
|
98
|
+
|
|
99
|
+
build:develop:
|
|
100
|
+
stage: build
|
|
101
|
+
cache:
|
|
102
|
+
key: $CI_PROJECT_DIR
|
|
103
|
+
paths:
|
|
104
|
+
- node_modules/
|
|
105
|
+
policy: pull
|
|
106
|
+
artifacts:
|
|
107
|
+
paths:
|
|
108
|
+
- projects/api/dist/
|
|
109
|
+
- projects/app/dist/
|
|
110
|
+
expire_in: 5 minutes
|
|
111
|
+
script:
|
|
112
|
+
- npm run init
|
|
113
|
+
- npm run build:develop
|
|
114
|
+
only:
|
|
115
|
+
- develop
|
|
116
|
+
|
|
117
|
+
#version_number:
|
|
118
|
+
# stage: version_number
|
|
119
|
+
# image: tarampampam/node:alpine
|
|
120
|
+
# script:
|
|
121
|
+
# - git config --global user.email $CI_EMAIL
|
|
122
|
+
# - git config --global user.name $CI_NAME
|
|
123
|
+
# - git config http.sslVerify "false"
|
|
124
|
+
# - npm install
|
|
125
|
+
# - git config receive.advertisePushOptions true
|
|
126
|
+
# - git checkout -B "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA"
|
|
127
|
+
# - npm run release
|
|
128
|
+
# - git push -o ci.skip --no-verify https://${CI_USER}:${CI_ACCESS_TOKEN}@gitlab.lenne.tech/products/akademie/master-minds.git --follow-tags test:test
|
|
129
|
+
# - git fetch && git checkout develop
|
|
130
|
+
# - git merge test
|
|
131
|
+
# - git push -o ci.skip --no-verify https://${CI_USER}:${CI_ACCESS_TOKEN}@gitlab.lenne.tech/products/akademie/master-minds.git --follow-tags develop:develop
|
|
132
|
+
# only:
|
|
133
|
+
# - test
|
|
134
|
+
|
|
135
|
+
docker_build_push_test:
|
|
136
|
+
stage: package
|
|
137
|
+
image: tiangolo/docker-with-compose
|
|
138
|
+
services:
|
|
139
|
+
- docker:dind
|
|
140
|
+
before_script:
|
|
141
|
+
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
|
142
|
+
script:
|
|
143
|
+
- FILE_NAME=$FILE_NAME_TEST STACK_NAME=$STACK_NAME APP_URL=$APP_URL_TEST IMAGE_TAG=test CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE sh build-push.sh
|
|
144
|
+
only:
|
|
145
|
+
- test
|
|
146
|
+
|
|
147
|
+
deploy_test:
|
|
148
|
+
stage: deploy
|
|
149
|
+
image: tiangolo/docker-with-compose
|
|
150
|
+
tags:
|
|
151
|
+
- docker-swarm
|
|
152
|
+
before_script:
|
|
153
|
+
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
|
154
|
+
script:
|
|
155
|
+
- FILE_NAME=$FILE_NAME_TEST STACK_NAME=$STACK_NAME APP_URL=$APP_URL_TEST IMAGE_TAG=test CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE sh deploy.sh
|
|
156
|
+
environment:
|
|
157
|
+
name: test
|
|
158
|
+
url: https://$APP_URL_TEST
|
|
159
|
+
only:
|
|
160
|
+
- test
|
|
161
|
+
|
|
162
|
+
docker_build_push_prod:
|
|
163
|
+
stage: package
|
|
164
|
+
image: tiangolo/docker-with-compose
|
|
165
|
+
dependencies:
|
|
166
|
+
- build:prod
|
|
167
|
+
before_script:
|
|
168
|
+
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
|
169
|
+
script:
|
|
170
|
+
- FILE_NAME=$FILE_NAME_PROD STACK_NAME=$STACK_NAME APP_URL=$APP_URL_PROD IMAGE_TAG=production CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE sh build-push.sh
|
|
171
|
+
only:
|
|
172
|
+
- main
|
|
173
|
+
|
|
174
|
+
deploy_prod:
|
|
175
|
+
stage: deploy
|
|
176
|
+
image: tiangolo/docker-with-compose
|
|
177
|
+
tags:
|
|
178
|
+
- docker-live
|
|
179
|
+
before_script:
|
|
180
|
+
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
|
181
|
+
script:
|
|
182
|
+
- FILE_NAME=$FILE_NAME_PROD STACK_NAME=$STACK_NAME APP_URL=$APP_URL_PROD IMAGE_TAG=production CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE sh deploy.sh
|
|
183
|
+
environment:
|
|
184
|
+
name: production
|
|
185
|
+
url: https://$APP_URL_PROD
|
|
186
|
+
only:
|
|
187
|
+
- main
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
FROM mhart/alpine-node:16.4.2
|
|
2
|
+
|
|
3
|
+
RUN mkdir -p /var/www/api
|
|
4
|
+
|
|
5
|
+
RUN apk --no-cache add curl
|
|
6
|
+
|
|
7
|
+
ADD ./projects/api/package.json /var/www/api/package.json
|
|
8
|
+
ADD ./projects/api/package-lock.json /var/www/api/package-lock.json
|
|
9
|
+
|
|
10
|
+
COPY ./projects/api/dist ./var/www/api
|
|
11
|
+
|
|
12
|
+
RUN cd /var/www/api && npm install && npm cache clean --force
|
|
13
|
+
|
|
14
|
+
HEALTHCHECK --interval=60s --retries=5 CMD curl --fail http://localhost:3000/meta/ || exit 1
|
|
15
|
+
|
|
16
|
+
WORKDIR /var/www/api
|
|
17
|
+
|
|
18
|
+
EXPOSE 3000
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
version: "3.7"
|
|
2
|
+
|
|
3
|
+
networks:
|
|
4
|
+
traefik-public:
|
|
5
|
+
external: true
|
|
6
|
+
overlay_mongo:
|
|
7
|
+
external: true
|
|
8
|
+
|
|
9
|
+
services:
|
|
10
|
+
api:
|
|
11
|
+
build:
|
|
12
|
+
context: .
|
|
13
|
+
dockerfile: Dockerfile
|
|
14
|
+
image: ${CI_REGISTRY_IMAGE?Variable not set}/api:${IMAGE_TAG?Variable not set}
|
|
15
|
+
restart: unless-stopped
|
|
16
|
+
container_name: swaktiv-api-${IMAGE_TAG?Variable not set}
|
|
17
|
+
networks:
|
|
18
|
+
- traefik-public
|
|
19
|
+
- overlay_mongo
|
|
20
|
+
deploy:
|
|
21
|
+
placement:
|
|
22
|
+
constraints:
|
|
23
|
+
- node.labels.traefik-public.traefik-public-certificates == true
|
|
24
|
+
update_config:
|
|
25
|
+
order: start-first
|
|
26
|
+
failure_action: rollback
|
|
27
|
+
delay: 10s
|
|
28
|
+
rollback_config:
|
|
29
|
+
parallelism: 0
|
|
30
|
+
order: stop-first
|
|
31
|
+
restart_policy:
|
|
32
|
+
condition: any
|
|
33
|
+
delay: 5s
|
|
34
|
+
max_attempts: 3
|
|
35
|
+
window: 120s
|
|
36
|
+
labels:
|
|
37
|
+
- traefik.enable=true
|
|
38
|
+
- traefik.docker.network=traefik-public
|
|
39
|
+
- traefik.constraint-label=traefik-public
|
|
40
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.rule=Host(`api.${APP_URL?Variable not set}`)
|
|
41
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.entrypoints=http
|
|
42
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.middlewares=https-redirect
|
|
43
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.rule=Host(`api.${APP_URL?Variable not set}`)
|
|
44
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.entrypoints=https
|
|
45
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.tls=true
|
|
46
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.tls.certresolver=le
|
|
47
|
+
- traefik.http.services.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api.loadbalancer.server.port=3000
|
|
48
|
+
entrypoint: ["/bin/sh", "-c"]
|
|
49
|
+
command:
|
|
50
|
+
- |
|
|
51
|
+
npm run migrate:develop:up
|
|
52
|
+
NODE_ENV=develop node ./src/main.js
|
|
53
|
+
|
|
54
|
+
app:
|
|
55
|
+
build:
|
|
56
|
+
context: .
|
|
57
|
+
dockerfile: Dockerfile.app
|
|
58
|
+
image: ${CI_REGISTRY_IMAGE?Variable not set}/app-ssr:${IMAGE_TAG?Variable not set}
|
|
59
|
+
restart: unless-stopped
|
|
60
|
+
container_name: swaktiv-app-${IMAGE_TAG?Variable not set}
|
|
61
|
+
entrypoint: ["/bin/sh", "-c"]
|
|
62
|
+
networks:
|
|
63
|
+
- traefik-public
|
|
64
|
+
deploy:
|
|
65
|
+
placement:
|
|
66
|
+
constraints:
|
|
67
|
+
- node.labels.traefik-public.traefik-public-certificates == true
|
|
68
|
+
update_config:
|
|
69
|
+
order: start-first
|
|
70
|
+
failure_action: rollback
|
|
71
|
+
delay: 10s
|
|
72
|
+
rollback_config:
|
|
73
|
+
parallelism: 0
|
|
74
|
+
order: stop-first
|
|
75
|
+
restart_policy:
|
|
76
|
+
condition: any
|
|
77
|
+
delay: 5s
|
|
78
|
+
max_attempts: 3
|
|
79
|
+
window: 120s
|
|
80
|
+
labels:
|
|
81
|
+
- traefik.enable=true
|
|
82
|
+
- traefik.docker.network=traefik-public
|
|
83
|
+
- traefik.constraint-label=traefik-public
|
|
84
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.rule=Host(`${APP_URL?Variable not set}`, `www.${APP_URL?Variable not set}`)
|
|
85
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.entrypoints=http
|
|
86
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.middlewares=https-redirect
|
|
87
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.rule=Host(`${APP_URL?Variable not set}`, `www.${APP_URL?Variable not set}`)
|
|
88
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.entrypoints=https
|
|
89
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.tls=true
|
|
90
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.tls.certresolver=le
|
|
91
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.regex=^https?://www.${APP_URL}/(.*)
|
|
92
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.replacement=https://${APP_URL}/$${1}
|
|
93
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.permanent=true
|
|
94
|
+
- traefik.http.services.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app.loadbalancer.server.port=4000
|
|
95
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.middlewares=${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect
|
|
96
|
+
|
|
97
|
+
command:
|
|
98
|
+
- |
|
|
99
|
+
NODE_ENV=develop node main.js
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
version: "3.7"
|
|
2
|
+
|
|
3
|
+
networks:
|
|
4
|
+
traefik-public:
|
|
5
|
+
external: true
|
|
6
|
+
overlay_mongo:
|
|
7
|
+
external: true
|
|
8
|
+
|
|
9
|
+
services:
|
|
10
|
+
api:
|
|
11
|
+
build:
|
|
12
|
+
context: .
|
|
13
|
+
dockerfile: Dockerfile
|
|
14
|
+
image: ${CI_REGISTRY_IMAGE?Variable not set}/api:${IMAGE_TAG?Variable not set}
|
|
15
|
+
restart: unless-stopped
|
|
16
|
+
container_name: <%= props.nameCamel %>-api-${IMAGE_TAG?Variable not set}
|
|
17
|
+
networks:
|
|
18
|
+
- traefik-public
|
|
19
|
+
- overlay_mongo
|
|
20
|
+
deploy:
|
|
21
|
+
update_config:
|
|
22
|
+
order: start-first
|
|
23
|
+
failure_action: rollback
|
|
24
|
+
delay: 10s
|
|
25
|
+
rollback_config:
|
|
26
|
+
parallelism: 0
|
|
27
|
+
order: stop-first
|
|
28
|
+
restart_policy:
|
|
29
|
+
condition: any
|
|
30
|
+
delay: 5s
|
|
31
|
+
max_attempts: 3
|
|
32
|
+
window: 120s
|
|
33
|
+
labels:
|
|
34
|
+
- traefik.enable=true
|
|
35
|
+
- traefik.docker.network=traefik-public
|
|
36
|
+
- traefik.constraint-label=traefik-public
|
|
37
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.rule=Host(`api.${APP_URL?Variable not set}`)
|
|
38
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.entrypoints=http
|
|
39
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.middlewares=https-redirect
|
|
40
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.rule=Host(`api.${APP_URL?Variable not set}`)
|
|
41
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.entrypoints=https
|
|
42
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.tls=true
|
|
43
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.tls.certresolver=le
|
|
44
|
+
- traefik.http.services.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api.loadbalancer.server.port=3000
|
|
45
|
+
entrypoint: ["/bin/sh", "-c"]
|
|
46
|
+
command:
|
|
47
|
+
- |
|
|
48
|
+
npm run migrate:prod:up
|
|
49
|
+
NODE_ENV=production node ./src/main.js
|
|
50
|
+
|
|
51
|
+
app:
|
|
52
|
+
build:
|
|
53
|
+
context: .
|
|
54
|
+
dockerfile: Dockerfile.app
|
|
55
|
+
image: ${CI_REGISTRY_IMAGE?Variable not set}/app-ssr:${IMAGE_TAG?Variable not set}
|
|
56
|
+
restart: unless-stopped
|
|
57
|
+
container_name: <%= props.nameCamel %>-app-${IMAGE_TAG?Variable not set}
|
|
58
|
+
entrypoint: ["/bin/sh", "-c"]
|
|
59
|
+
networks:
|
|
60
|
+
- traefik-public
|
|
61
|
+
deploy:
|
|
62
|
+
update_config:
|
|
63
|
+
order: start-first
|
|
64
|
+
failure_action: rollback
|
|
65
|
+
delay: 10s
|
|
66
|
+
rollback_config:
|
|
67
|
+
parallelism: 0
|
|
68
|
+
order: stop-first
|
|
69
|
+
restart_policy:
|
|
70
|
+
condition: any
|
|
71
|
+
delay: 5s
|
|
72
|
+
max_attempts: 3
|
|
73
|
+
window: 120s
|
|
74
|
+
labels:
|
|
75
|
+
- traefik.enable=true
|
|
76
|
+
- traefik.docker.network=traefik-public
|
|
77
|
+
- traefik.constraint-label=traefik-public
|
|
78
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.rule=Host(`${APP_URL?Variable not set}`, `www.${APP_URL?Variable not set}`)
|
|
79
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.entrypoints=http
|
|
80
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.middlewares=https-redirect
|
|
81
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.rule=Host(`${APP_URL?Variable not set}`, `www.${APP_URL?Variable not set}`)
|
|
82
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.entrypoints=https
|
|
83
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.tls=true
|
|
84
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.tls.certresolver=le
|
|
85
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.regex=^https?://www.${APP_URL}/(.*)
|
|
86
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.replacement=https://${APP_URL}/$${1}
|
|
87
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.permanent=true
|
|
88
|
+
- traefik.http.services.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app.loadbalancer.server.port=4000
|
|
89
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.middlewares=${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect
|
|
90
|
+
command:
|
|
91
|
+
- |
|
|
92
|
+
NODE_ENV="production" node main.js
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
version: "3.7"
|
|
2
|
+
|
|
3
|
+
networks:
|
|
4
|
+
traefik-public:
|
|
5
|
+
external: true
|
|
6
|
+
overlay_mongo:
|
|
7
|
+
external: true
|
|
8
|
+
|
|
9
|
+
services:
|
|
10
|
+
api:
|
|
11
|
+
build:
|
|
12
|
+
context: .
|
|
13
|
+
dockerfile: Dockerfile
|
|
14
|
+
image: ${CI_REGISTRY_IMAGE?Variable not set}/api:${IMAGE_TAG?Variable not set}
|
|
15
|
+
restart: unless-stopped
|
|
16
|
+
container_name: <%= props.nameCamel %>-api-${IMAGE_TAG?Variable not set}
|
|
17
|
+
networks:
|
|
18
|
+
- traefik-public
|
|
19
|
+
- overlay_mongo
|
|
20
|
+
deploy:
|
|
21
|
+
placement:
|
|
22
|
+
constraints:
|
|
23
|
+
- node.labels.traefik-public.traefik-public-certificates == true
|
|
24
|
+
update_config:
|
|
25
|
+
order: start-first
|
|
26
|
+
failure_action: rollback
|
|
27
|
+
delay: 10s
|
|
28
|
+
rollback_config:
|
|
29
|
+
parallelism: 0
|
|
30
|
+
order: stop-first
|
|
31
|
+
restart_policy:
|
|
32
|
+
condition: any
|
|
33
|
+
delay: 5s
|
|
34
|
+
max_attempts: 3
|
|
35
|
+
window: 120s
|
|
36
|
+
labels:
|
|
37
|
+
- traefik.enable=true
|
|
38
|
+
- traefik.docker.network=traefik-public
|
|
39
|
+
- traefik.constraint-label=traefik-public
|
|
40
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.rule=Host(`api.${APP_URL?Variable not set}`)
|
|
41
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.entrypoints=http
|
|
42
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-http.middlewares=https-redirect
|
|
43
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.rule=Host(`api.${APP_URL?Variable not set}`)
|
|
44
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.entrypoints=https
|
|
45
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.tls=true
|
|
46
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api-https.tls.certresolver=le
|
|
47
|
+
- traefik.http.services.${STACK_NAME?Variable not set}-${IMAGE_TAG}-api.loadbalancer.server.port=3000
|
|
48
|
+
entrypoint: ["/bin/sh", "-c"]
|
|
49
|
+
command:
|
|
50
|
+
- |
|
|
51
|
+
npm run migrate:test:up
|
|
52
|
+
NODE_ENV=test node ./src/main.js
|
|
53
|
+
|
|
54
|
+
app:
|
|
55
|
+
build:
|
|
56
|
+
context: .
|
|
57
|
+
dockerfile: Dockerfile.app
|
|
58
|
+
image: ${CI_REGISTRY_IMAGE?Variable not set}/app-ssr:${IMAGE_TAG?Variable not set}
|
|
59
|
+
restart: unless-stopped
|
|
60
|
+
container_name: <%= props.nameCamel %>-app-${IMAGE_TAG?Variable not set}
|
|
61
|
+
entrypoint: ["/bin/sh", "-c"]
|
|
62
|
+
networks:
|
|
63
|
+
- traefik-public
|
|
64
|
+
deploy:
|
|
65
|
+
placement:
|
|
66
|
+
constraints:
|
|
67
|
+
- node.labels.traefik-public.traefik-public-certificates == true
|
|
68
|
+
update_config:
|
|
69
|
+
order: start-first
|
|
70
|
+
failure_action: rollback
|
|
71
|
+
delay: 10s
|
|
72
|
+
rollback_config:
|
|
73
|
+
parallelism: 0
|
|
74
|
+
order: stop-first
|
|
75
|
+
restart_policy:
|
|
76
|
+
condition: any
|
|
77
|
+
delay: 5s
|
|
78
|
+
max_attempts: 3
|
|
79
|
+
window: 120s
|
|
80
|
+
labels:
|
|
81
|
+
- traefik.enable=true
|
|
82
|
+
- traefik.docker.network=traefik-public
|
|
83
|
+
- traefik.constraint-label=traefik-public
|
|
84
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.rule=Host(`${APP_URL?Variable not set}`, `www.${APP_URL?Variable not set}`)
|
|
85
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.entrypoints=http
|
|
86
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-http.middlewares=https-redirect
|
|
87
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.rule=Host(`${APP_URL?Variable not set}`, `www.${APP_URL?Variable not set}`)
|
|
88
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.entrypoints=https
|
|
89
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.tls=true
|
|
90
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.tls.certresolver=le
|
|
91
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.regex=^https?://www.${APP_URL}/(.*)
|
|
92
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.replacement=https://${APP_URL}/$${1}
|
|
93
|
+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect.redirectregex.permanent=true
|
|
94
|
+
- traefik.http.services.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app.loadbalancer.server.port=4000
|
|
95
|
+
- traefik.http.routers.${STACK_NAME?Variable not set}-${IMAGE_TAG}-app-https.middlewares=${STACK_NAME?Variable not set}-${IMAGE_TAG}-redirect
|
|
96
|
+
command:
|
|
97
|
+
- |
|
|
98
|
+
NODE_ENV=test node main.js
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#! /usr/bin/env sh
|
|
2
|
+
|
|
3
|
+
# Exit in case of error
|
|
4
|
+
set -e
|
|
5
|
+
|
|
6
|
+
STACK_NAME=${STACK_NAME?Variable not set} \
|
|
7
|
+
APP_URL=${APP_URL?Variable not set} \
|
|
8
|
+
IMAGE_TAG=${IMAGE_TAG?Variable not set} \
|
|
9
|
+
CI_REGISTRY_IMAGE=${CI_REGISTRY_IMAGE?Variable not set} \
|
|
10
|
+
docker compose \
|
|
11
|
+
-f ${FILE_NAME?Variable not set} \
|
|
12
|
+
build
|
|
13
|
+
|
|
14
|
+
STACK_NAME=${STACK_NAME?Variable not set} \
|
|
15
|
+
APP_URL=${APP_URL?Variable not set} \
|
|
16
|
+
IMAGE_TAG=${IMAGE_TAG?Variable not set} \
|
|
17
|
+
CI_REGISTRY_IMAGE=${CI_REGISTRY_IMAGE?Variable not set} \
|
|
18
|
+
docker compose \
|
|
19
|
+
-f ${FILE_NAME?Variable not set} \
|
|
20
|
+
push
|
|
@@ -1,21 +1,18 @@
|
|
|
1
|
+
import { Restricted, RoleEnum } from '@lenne.tech/nest-server';
|
|
1
2
|
import { Field, InputType } from '@nestjs/graphql';
|
|
2
3
|
import { IsOptional } from 'class-validator';
|
|
3
|
-
import { <%= props.namePascal %>Input } from './<%= props.nameKebab %>.input'
|
|
4
|
+
import { <%= props.namePascal %>Input } from './<%= props.nameKebab %>.input';<%- props.imports %>
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* <%= props.namePascal %> create input
|
|
7
9
|
*/
|
|
10
|
+
@Restricted(RoleEnum.ADMIN)
|
|
8
11
|
@InputType({ description: 'Input data to create a new <%= props.namePascal %>' })
|
|
9
12
|
export class <%= props.namePascal %>CreateInput extends <%= props.namePascal %>Input {
|
|
10
13
|
|
|
11
14
|
// ===================================================================================================================
|
|
12
15
|
// Properties
|
|
13
16
|
// ===================================================================================================================
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Description of the properties
|
|
17
|
-
*/
|
|
18
|
-
@Field(() => [String], { description: 'Description of the properties', nullable: true })
|
|
19
|
-
@IsOptional()
|
|
20
|
-
properties?: string[];
|
|
17
|
+
<%- props.props %>
|
|
21
18
|
}
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import { Restricted, RoleEnum } from '@lenne.tech/nest-server';
|
|
2
2
|
import { Field, InputType } from '@nestjs/graphql';
|
|
3
|
-
import { IsOptional } from 'class-validator'
|
|
3
|
+
import { IsOptional } from 'class-validator';<%- props.imports %>
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* <%= props.namePascal %> input
|
|
7
7
|
*/
|
|
8
|
+
@Restricted(RoleEnum.ADMIN)
|
|
8
9
|
@InputType({ description: 'Input data to update an existing <%= props.namePascal %>' })
|
|
9
10
|
export class <%= props.namePascal %>Input {
|
|
10
11
|
|
|
11
12
|
// ===================================================================================================================
|
|
12
13
|
// Properties
|
|
13
14
|
// ===================================================================================================================
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Description of the properties
|
|
17
|
-
*/
|
|
18
|
-
@Restricted(RoleEnum.ADMIN, RoleEnum.S_CREATOR)
|
|
19
|
-
@Field(() => [String], { description: 'Description of the properties', nullable: true })
|
|
20
|
-
@IsOptional()
|
|
21
|
-
properties?: string[];
|
|
15
|
+
<%- props.props %>
|
|
22
16
|
}
|
|
@@ -3,13 +3,13 @@ import { Field, ObjectType } from '@nestjs/graphql';
|
|
|
3
3
|
import { Prop, Schema as MongooseSchema, SchemaFactory } from '@nestjs/mongoose';
|
|
4
4
|
import { Document, Schema } from 'mongoose';
|
|
5
5
|
import { PersistenceModel } from '../../common/models/persistence.model';
|
|
6
|
-
import { User } from '../user/user.model';
|
|
7
6
|
|
|
8
7
|
export type <%= props.namePascal %>Document = <%= props.namePascal %> & Document;
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* <%= props.namePascal %> model
|
|
12
11
|
*/
|
|
12
|
+
@Restricted(RoleEnum.ADMIN)
|
|
13
13
|
@ObjectType({ description: '<%= props.namePascal %>' })
|
|
14
14
|
@MongooseSchema({ timestamps: true })
|
|
15
15
|
export class <%= props.namePascal %> extends PersistenceModel {
|
|
@@ -17,24 +17,7 @@ export class <%= props.namePascal %> extends PersistenceModel {
|
|
|
17
17
|
// ===================================================================================================================
|
|
18
18
|
// Properties
|
|
19
19
|
// ===================================================================================================================
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Description of properties
|
|
23
|
-
*/
|
|
24
|
-
@Restricted(RoleEnum.ADMIN, RoleEnum.S_CREATOR)
|
|
25
|
-
@Field(() => [String], { description: 'Properties of <%= props.namePascal %>', nullable: 'items'})
|
|
26
|
-
@Prop([String])
|
|
27
|
-
properties: string[] = undefined;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* User how has tested the <%= props.namePascal %>
|
|
31
|
-
*/
|
|
32
|
-
@Field(() => User, {
|
|
33
|
-
description: 'User who has tested the <%= props.namePascal %>',
|
|
34
|
-
nullable: true,
|
|
35
|
-
})
|
|
36
|
-
@Prop({ type: Schema.Types.ObjectId, ref: 'User' })
|
|
37
|
-
testedBy: User = undefined;
|
|
20
|
+
<%- props.props %>
|
|
38
21
|
|
|
39
22
|
// ===================================================================================================================
|
|
40
23
|
// Methods
|
|
@@ -45,7 +28,7 @@ export class <%= props.namePascal %> extends PersistenceModel {
|
|
|
45
28
|
*/
|
|
46
29
|
init() {
|
|
47
30
|
super.init();
|
|
48
|
-
this.
|
|
31
|
+
// this.xxx = [];
|
|
49
32
|
return this;
|
|
50
33
|
}
|
|
51
34
|
|
|
@@ -56,7 +39,7 @@ export class <%= props.namePascal %> extends PersistenceModel {
|
|
|
56
39
|
*/
|
|
57
40
|
map(input) {
|
|
58
41
|
super.map(input);
|
|
59
|
-
return
|
|
42
|
+
return <%- props.mappings %>
|
|
60
43
|
}
|
|
61
44
|
}
|
|
62
45
|
|
|
@@ -13,6 +13,7 @@ import { <%= props.namePascal %>Service } from './<%= props.nameKebab %>.service
|
|
|
13
13
|
/**
|
|
14
14
|
* Resolver to process with <%= props.namePascal %> data
|
|
15
15
|
*/
|
|
16
|
+
@Roles(RoleEnum.ADMIN)
|
|
16
17
|
@Resolver(() => <%= props.namePascal %>)
|
|
17
18
|
export class <%= props.namePascal %>Resolver {
|
|
18
19
|
|
|
@@ -35,7 +36,7 @@ export class <%= props.namePascal %>Resolver {
|
|
|
35
36
|
@Query(() => FindAndCount<%= props.namePascal %>sResult, { description: 'Find <%= props.namePascal %>s (via filter)' })
|
|
36
37
|
async findAndCount<%= props.namePascal %>s(@Info() info: GraphQLResolveInfo, @Args() args?: FilterArgs) {
|
|
37
38
|
return await this.<%= props.nameCamel %>Service.findAndCount(args, {
|
|
38
|
-
fieldSelection: { info, select: 'findAndCount<%= props.namePascal %>s' },
|
|
39
|
+
fieldSelection: { info, select: 'findAndCount<%= props.namePascal %>s.items' },
|
|
39
40
|
inputType: FilterArgs,
|
|
40
41
|
});
|
|
41
42
|
}
|