@lenne.tech/cli 0.0.79 → 0.0.80
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/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/package.json +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
/**
|
|
14
|
+
* Create a new server module
|
|
15
|
+
*/
|
|
16
|
+
const NewCommand = {
|
|
17
|
+
name: 'create',
|
|
18
|
+
alias: ['dc'],
|
|
19
|
+
description: 'Creates a new deployment for mono repository',
|
|
20
|
+
hidden: false,
|
|
21
|
+
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
+
// Retrieve the tools we need
|
|
23
|
+
const { filesystem, helper, parameters, print: { info, spin, success }, strings: { kebabCase, pascalCase, camelCase }, prompt: { confirm }, system, template, } = toolbox;
|
|
24
|
+
// Start timer
|
|
25
|
+
const timer = system.startTimer();
|
|
26
|
+
// Info
|
|
27
|
+
info('Create a new deployment');
|
|
28
|
+
// Get name
|
|
29
|
+
const name = yield helper.getInput(parameters.first, {
|
|
30
|
+
name: 'project name',
|
|
31
|
+
});
|
|
32
|
+
if (!name) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Get url
|
|
36
|
+
const url = yield helper.getInput(parameters.second, {
|
|
37
|
+
name: 'url for deployment',
|
|
38
|
+
});
|
|
39
|
+
if (!name) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const gitHub = yield confirm(`Add GitHub pipeline?`);
|
|
43
|
+
const gitLab = yield confirm(`Add GitLab pipeline?`);
|
|
44
|
+
// Set up initial props (to pass into templates)
|
|
45
|
+
const nameCamel = camelCase(name);
|
|
46
|
+
const nameKebab = kebabCase(name);
|
|
47
|
+
const namePascal = pascalCase(name);
|
|
48
|
+
// Check if directory
|
|
49
|
+
const cwd = filesystem.cwd();
|
|
50
|
+
const generateSpinner = spin('Generate files');
|
|
51
|
+
yield template.generate({
|
|
52
|
+
template: 'deployment/scripts/build-push.sh.ejs',
|
|
53
|
+
target: (0, path_1.join)(cwd, 'scripts', 'build-push.sh'),
|
|
54
|
+
props: { nameCamel, nameKebab, namePascal },
|
|
55
|
+
});
|
|
56
|
+
yield template.generate({
|
|
57
|
+
template: 'deployment/scripts/deploy.sh.ejs',
|
|
58
|
+
target: (0, path_1.join)(cwd, 'scripts', 'deploy.sh'),
|
|
59
|
+
props: { nameCamel, nameKebab, namePascal },
|
|
60
|
+
});
|
|
61
|
+
yield template.generate({
|
|
62
|
+
template: 'deployment/Dockerfile.ejs',
|
|
63
|
+
target: (0, path_1.join)(cwd, 'Dockerfile'),
|
|
64
|
+
props: { nameCamel, nameKebab, namePascal },
|
|
65
|
+
});
|
|
66
|
+
yield template.generate({
|
|
67
|
+
template: 'deployment/Dockerfile.app.ejs',
|
|
68
|
+
target: (0, path_1.join)(cwd, 'Dockerfile.app'),
|
|
69
|
+
props: { nameCamel, nameKebab, namePascal },
|
|
70
|
+
});
|
|
71
|
+
yield template.generate({
|
|
72
|
+
template: 'deployment/docker-compose.develop.yml.ejs',
|
|
73
|
+
target: (0, path_1.join)(cwd, 'docker-compose.develop.yml'),
|
|
74
|
+
props: { nameCamel, nameKebab, namePascal },
|
|
75
|
+
});
|
|
76
|
+
yield template.generate({
|
|
77
|
+
template: 'deployment/docker-compose.test.yml.ejs',
|
|
78
|
+
target: (0, path_1.join)(cwd, 'docker-compose.test.yml'),
|
|
79
|
+
props: { nameCamel, nameKebab, namePascal },
|
|
80
|
+
});
|
|
81
|
+
yield template.generate({
|
|
82
|
+
template: 'deployment/docker-compose.prod.yml.ejs',
|
|
83
|
+
target: (0, path_1.join)(cwd, 'docker-compose.prod.yml'),
|
|
84
|
+
props: { nameCamel, nameKebab, namePascal },
|
|
85
|
+
});
|
|
86
|
+
if (gitHub) {
|
|
87
|
+
yield template.generate({
|
|
88
|
+
template: 'deployment/.github/workflows/pre-release.yml.ejs',
|
|
89
|
+
target: (0, path_1.join)(cwd, '.github', 'workflows', 'pre-release.yml'),
|
|
90
|
+
props: { nameCamel, nameKebab, namePascal, url },
|
|
91
|
+
});
|
|
92
|
+
yield template.generate({
|
|
93
|
+
template: 'deployment/.github/workflows/release.yml.ejs',
|
|
94
|
+
target: (0, path_1.join)(cwd, '.github', 'workflows', 'release.yml'),
|
|
95
|
+
props: { nameCamel, nameKebab, namePascal, url },
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (gitLab) {
|
|
99
|
+
yield template.generate({
|
|
100
|
+
template: 'deployment/.gitlab-ci.yml.ejs',
|
|
101
|
+
target: (0, path_1.join)(cwd, '.gitlab-ci.yml'),
|
|
102
|
+
props: { nameCamel, nameKebab, namePascal, url },
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
generateSpinner.succeed('Files generated');
|
|
106
|
+
// We're done, so show what to do next
|
|
107
|
+
info(``);
|
|
108
|
+
success(`Generated deployment for ${namePascal} in ${helper.msToMinutesAndSeconds(timer())}m.`);
|
|
109
|
+
info(``);
|
|
110
|
+
if (!toolbox.parameters.options.fromGluegunMenu) {
|
|
111
|
+
process.exit();
|
|
112
|
+
}
|
|
113
|
+
// For tests
|
|
114
|
+
return `new deployment ${name}`;
|
|
115
|
+
}),
|
|
116
|
+
};
|
|
117
|
+
exports.default = NewCommand;
|
|
118
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL2RlcGxveW1lbnQvY3JlYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQ0EsK0JBQTRCO0FBRzVCOztHQUVHO0FBQ0gsTUFBTSxVQUFVLEdBQW1CO0lBQ2pDLElBQUksRUFBRSxRQUFRO0lBQ2QsS0FBSyxFQUFFLENBQUMsSUFBSSxDQUFDO0lBQ2IsV0FBVyxFQUFFLDhDQUE4QztJQUMzRCxNQUFNLEVBQUUsS0FBSztJQUNiLEdBQUcsRUFBRSxDQUFPLE9BQStCLEVBQUUsRUFBRTtRQUM3Qyw2QkFBNkI7UUFDN0IsTUFBTSxFQUNKLFVBQVUsRUFDVixNQUFNLEVBQ04sVUFBVSxFQUNWLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLEVBQzlCLE9BQU8sRUFBRSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLEVBQzdDLE1BQU0sRUFBRSxFQUFFLE9BQU8sRUFBRSxFQUNuQixNQUFNLEVBQ04sUUFBUSxHQUNULEdBQUcsT0FBTyxDQUFDO1FBRVosY0FBYztRQUNkLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUVsQyxPQUFPO1FBQ1AsSUFBSSxDQUFDLHlCQUF5QixDQUFDLENBQUM7UUFFaEMsV0FBVztRQUNYLE1BQU0sSUFBSSxHQUFHLE1BQU0sTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFO1lBQ25ELElBQUksRUFBRSxjQUFjO1NBQ3JCLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDVCxPQUFPO1NBQ1I7UUFFRCxVQUFVO1FBQ1YsTUFBTSxHQUFHLEdBQUcsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUU7WUFDbkQsSUFBSSxFQUFFLG9CQUFvQjtTQUMzQixDQUFD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
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
/**
|
|
13
|
+
* Deployment commands
|
|
14
|
+
*/
|
|
15
|
+
module.exports = {
|
|
16
|
+
name: 'deployment',
|
|
17
|
+
alias: ['d'],
|
|
18
|
+
description: 'Server commands',
|
|
19
|
+
hidden: true,
|
|
20
|
+
run: (toolbox) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
+
yield toolbox.helper.showMenu('deployment');
|
|
22
|
+
return 'deployment';
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95bWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb21tYW5kcy9kZXBsb3ltZW50L2RlcGxveW1lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFFQTs7R0FFRztBQUNILE1BQU0sQ0FBQyxPQUFPLEdBQUc7SUFDZixJQUFJLEVBQUUsWUFBWTtJQUNsQixLQUFLLEVBQUUsQ0FBQyxHQUFHLENBQUM7SUFDWixXQUFXLEVBQUUsaUJBQWlCO0lBQzlCLE1BQU0sRUFBRSxJQUFJO0lBQ1osR0FBRyxFQUFFLENBQU8sT0FBK0IsRUFBRSxFQUFFO1FBQzdDLE1BQU0sT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDNUMsT0FBTyxZQUFZLENBQUM7SUFDdEIsQ0FBQyxDQUFBO0NBQ0YsQ0FBQyJ9
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types:
|
|
6
|
+
- prereleased
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
deploy:
|
|
13
|
+
runs-on: [self-hosted, docker-live]
|
|
14
|
+
env:
|
|
15
|
+
STACK_NAME: <%= props.nameCamel %>
|
|
16
|
+
APP_URL: test.<%= props.url %>
|
|
17
|
+
CI_REGISTRY_IMAGE: localhost:5000/<%= props.nameCamel %>
|
|
18
|
+
FILE_NAME: docker-compose.test.yml
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v1
|
|
21
|
+
- name: Use Node.js 18
|
|
22
|
+
uses: actions/setup-node@v1
|
|
23
|
+
with:
|
|
24
|
+
node-version: 18
|
|
25
|
+
- name: Install
|
|
26
|
+
run: npm run init
|
|
27
|
+
- name: Build app
|
|
28
|
+
run: npm run build:test
|
|
29
|
+
- name: Build docker
|
|
30
|
+
run: STACK_NAME=${{env.STACK_NAME}} APP_URL=${{env.APP_URL}} IMAGE_TAG=test CI_REGISTRY_IMAGE=${{env.CI_REGISTRY_IMAGE}} sh build-push.sh
|
|
31
|
+
- name: Deploy
|
|
32
|
+
run: FILE_NAME=${{env.FILE_NAME}} STACK_NAME=${{env.STACK_NAME}} APP_URL=${{env.APP_URL}} IMAGE_TAG=test CI_REGISTRY_IMAGE=${{env.CI_REGISTRY_IMAGE}} sh deploy.sh
|
|
33
|
+
- name: Deploy notification
|
|
34
|
+
if: always()
|
|
35
|
+
uses: adamkdean/simple-slack-notify@master
|
|
36
|
+
with:
|
|
37
|
+
channel: "#deployments"
|
|
38
|
+
status: ${{ job.status }}
|
|
39
|
+
success_text: "Version (#${{ github.event.release.tag_name }}) von <%= props.nameCamel %> wurde erfolgreich auf *Test* deployed."
|
|
40
|
+
failure_text: "Testversion (#${{ github.event.release.tag_name }}) von <%= props.nameCamel %> ist fehlgeschlagen."
|
|
41
|
+
cancelled_text: "Testversion (#${{ github.event.release.tag_name }}) von <%= props.nameCamel %> wurde abgebrochen."
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Deploy
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types:
|
|
6
|
+
- released
|
|
7
|
+
|
|
8
|
+
env:
|
|
9
|
+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
deploy:
|
|
13
|
+
runs-on: [self-hosted, docker-live-swaktiv]
|
|
14
|
+
env:
|
|
15
|
+
STACK_NAME: <%= props.nameCamel %>
|
|
16
|
+
APP_URL: <%= props.url %>
|
|
17
|
+
CI_REGISTRY_IMAGE: localhost:5000/<%= props.nameCamel %>
|
|
18
|
+
FILE_NAME: docker-compose.prod.yml
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v1
|
|
21
|
+
- name: Use Node.js 18
|
|
22
|
+
uses: actions/setup-node@v1
|
|
23
|
+
with:
|
|
24
|
+
node-version: 18
|
|
25
|
+
- name: Install
|
|
26
|
+
run: npm run init
|
|
27
|
+
- name: Build app
|
|
28
|
+
run: npm run build
|
|
29
|
+
- name: Build docker
|
|
30
|
+
run: STACK_NAME=${{env.STACK_NAME}} APP_URL=${{env.APP_URL}} IMAGE_TAG=latest CI_REGISTRY_IMAGE=${{env.CI_REGISTRY_IMAGE}} sh build-push.sh
|
|
31
|
+
- name: Deploy
|
|
32
|
+
run: FILE_NAME=${{env.FILE_NAME}} STACK_NAME=${{env.STACK_NAME}} APP_URL=${{env.APP_URL}} IMAGE_TAG=latest CI_REGISTRY_IMAGE=${{env.CI_REGISTRY_IMAGE}} sh deploy.sh
|
|
33
|
+
- name: Deploy notification
|
|
34
|
+
if: always()
|
|
35
|
+
uses: adamkdean/simple-slack-notify@master
|
|
36
|
+
with:
|
|
37
|
+
channel: "#deployments"
|
|
38
|
+
status: ${{ job.status }}
|
|
39
|
+
success_text: "Version (#${{ github.event.release.tag_name }}) von <%= props.nameCamel %> wurde erfolgreich auf *Live* deployed."
|
|
40
|
+
failure_text: "Release (#${{ github.event.release.tag_name }}) von <%= props.nameCamel %> ist fehlgeschlagen."
|
|
41
|
+
cancelled_text: "Release (#${{ github.event.release.tag_name }}) von <%= props.nameCamel %> wurde abgebrochen."
|
|
@@ -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
|