@leverege/build-tools 2.21.8 → 2.21.9-nick.2
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/.env.temp +18 -0
- package/.firebaserc +40 -0
- package/.firebasercizg +47 -0
- package/.vscode/launch.json +18 -0
- package/firebase.json +180 -0
- package/lib/server/firebaseDeploy.js +109 -14
- package/lib/web/firebaseDeploy.js +109 -14
- package/package.json +2 -1
- package/secrets/dev-obd.env +13 -0
- package/secrets/dev.env +12 -0
- package/secrets/prd-obd.env +12 -0
- package/secrets/prd.env +10 -0
- package/secrets/shared.env +6 -0
- package/secrets/stg-obd.env +10 -0
- package/secrets/stg.env +9 -0
- package/src/firebaseDeploy.mjs +106 -12
package/.env.temp
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
THEFT_RECOVERY_URL='theft.recovermycar.com'
|
|
2
|
+
MAPBOX_APIKEY=pk.eyJ1IjoibGV2ZXJlZ2UiLCJhIjoiY2p1Y3E0cWpkMG15azQzbnFzaDY2dmhiMSJ9.7N25h5jsjO2Aq_YmiLrAJw
|
|
3
|
+
APPEARANCE_PROJECT_ID=7b2GTbmsZj3f5VdFpjGM8O
|
|
4
|
+
INTERCOM_APP_ID='ec0qbuwi'
|
|
5
|
+
LOCATOR_ALIAS_KEY='serialNumber'
|
|
6
|
+
RECOVR_BILLING_MODULE='recovrBilling'
|
|
7
|
+
IMAGINE_HOST=https://leverege-sandbox-imagine-api.leverege.com
|
|
8
|
+
RECOVR_HOST=https://dev-recovr-notify.leverege.com
|
|
9
|
+
# RECOVR_HOST=http://localhost:8296
|
|
10
|
+
SYSTEM_ID=0UTmPFvRHXYLMlT4Kl2z1K
|
|
11
|
+
PROJECT_ID=08HBeHEYGxu5Bg4TCCnAAV
|
|
12
|
+
VEHICLE_NETWORK_ID='dev-dealership-vehicles'
|
|
13
|
+
CONSUMER_VEHICLE_NETWORK_ID='dev-customer-vehicles'
|
|
14
|
+
LOCATOR_NETWORK_ID='dev-recovr-tracker'
|
|
15
|
+
BEACON_NETWORK_ID='dev-dealership-beacons'
|
|
16
|
+
SALE_LOCATION_PARENT_PATH=sales
|
|
17
|
+
CONSUMER_LOCATION_ID=1KceIcZlVWrOBvCzsEXYud
|
|
18
|
+
IS_DEV=true
|
package/.firebaserc
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"projects": {
|
|
3
|
+
"default": "leverege-sandbox",
|
|
4
|
+
"stg-recovr-auto": "stg-recovr-auto",
|
|
5
|
+
"prd-recovr-auto":"prd-recovr-auto"
|
|
6
|
+
},
|
|
7
|
+
"targets": {
|
|
8
|
+
"leverege-sandbox": {
|
|
9
|
+
"hosting": {
|
|
10
|
+
"recovr": [
|
|
11
|
+
"dev"
|
|
12
|
+
],
|
|
13
|
+
"dev-obd-recovr": [
|
|
14
|
+
"dev-obd"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"stg-recovr-auto": {
|
|
19
|
+
"hosting": {
|
|
20
|
+
"stg-recovr": [
|
|
21
|
+
"stg"
|
|
22
|
+
],
|
|
23
|
+
"stg-obd-recovr": [
|
|
24
|
+
"stg-obd"
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"prd-recovr-auto": {
|
|
29
|
+
"hosting": {
|
|
30
|
+
"recovr-auto": [
|
|
31
|
+
"prd"
|
|
32
|
+
],
|
|
33
|
+
"prd-obd-recovr":[
|
|
34
|
+
"prd-obd"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"production": true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
package/.firebasercizg
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"projects": {
|
|
3
|
+
"default": "leverege-sandbox",
|
|
4
|
+
"dev-keys": "leverege-dev-nick",
|
|
5
|
+
"prd-indoor-zoning" : "prd-indoor-zoning"
|
|
6
|
+
},
|
|
7
|
+
"targets": {
|
|
8
|
+
"leverege-sandbox": {
|
|
9
|
+
"hosting": {
|
|
10
|
+
"dev-izg": [
|
|
11
|
+
"dev-izg"
|
|
12
|
+
],
|
|
13
|
+
"dev-olive-indoor-zoning": [
|
|
14
|
+
"dev-olive-indoor-zoning"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"leverege-dev-nick": {
|
|
19
|
+
"hosting": {
|
|
20
|
+
"dev-keys": [
|
|
21
|
+
"dev-keys"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"prd-indoor-zoning": {
|
|
26
|
+
"hosting": {
|
|
27
|
+
"prd-indoor-zoning-ui222": [
|
|
28
|
+
"prd-indoor-zoning-ui"
|
|
29
|
+
],
|
|
30
|
+
"prd-olive-indoor-zoning-ui222": [
|
|
31
|
+
"prd-olive-indoor-zoning-ui"
|
|
32
|
+
],
|
|
33
|
+
"prd-keys222": [
|
|
34
|
+
"prd-keys"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"production": true
|
|
38
|
+
},
|
|
39
|
+
"stg-indoor-zoning-pen-test": {
|
|
40
|
+
"hosting": {
|
|
41
|
+
"stg-indoor-zoning-ui": [
|
|
42
|
+
"stg-indoor-zoning-ui"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"type": "node",
|
|
9
|
+
"request": "launch",
|
|
10
|
+
"name": "firebase deploy",
|
|
11
|
+
"skipFiles": [
|
|
12
|
+
"<node_internals>/**"
|
|
13
|
+
],
|
|
14
|
+
"program": "${workspaceFolder}/src/firebaseDeploy.mjs",
|
|
15
|
+
"console": "integratedTerminal"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/firebase.json
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hosting": [
|
|
3
|
+
{
|
|
4
|
+
"site":"dev-izg",
|
|
5
|
+
"public": "dist",
|
|
6
|
+
"ignore": [
|
|
7
|
+
"firebase.json",
|
|
8
|
+
"**/.*",
|
|
9
|
+
"**/node_modules/**"
|
|
10
|
+
],
|
|
11
|
+
"rewrites": [
|
|
12
|
+
{
|
|
13
|
+
"source": "**",
|
|
14
|
+
"destination": "/index.html"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"headers": {
|
|
18
|
+
"X-Content-Type-Options": "nosniff",
|
|
19
|
+
"X-XSS-Protection": "1; mode=block",
|
|
20
|
+
"X-Frame-Options": "deny",
|
|
21
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: leverege-sandbox-imagine-api.leverege.com *.mapbox.com *.firebaseio.com wss://*.firebaseio.com *.googleapis.com *.intercom.io wss://*.intercom.io maxcdn.bootstrapcdn.com *.intercomcdn.com *.gstatic.com;",
|
|
22
|
+
"Referrer-Policy":"no-referrer"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"site":"dev-keys",
|
|
27
|
+
"public": "dist",
|
|
28
|
+
"ignore": [
|
|
29
|
+
"firebase.json",
|
|
30
|
+
"**/.*",
|
|
31
|
+
"**/node_modules/**"
|
|
32
|
+
],
|
|
33
|
+
"rewrites": [
|
|
34
|
+
{
|
|
35
|
+
"source": "**",
|
|
36
|
+
"destination": "/index.html"
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"headers": {
|
|
40
|
+
"X-Content-Type-Options": "nosniff",
|
|
41
|
+
"X-XSS-Protection": "1; mode=block",
|
|
42
|
+
"X-Frame-Options": "deny",
|
|
43
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: leverege-sandbox-imagine-api.leverege.com *.mapbox.com *.firebaseio.com wss://*.firebaseio.com *.googleapis.com *.intercom.io wss://*.intercom.io maxcdn.bootstrapcdn.com *.intercomcdn.com *.gstatic.com;",
|
|
44
|
+
"Referrer-Policy":"no-referrer"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"site":"dev-keys",
|
|
49
|
+
"public": "dist",
|
|
50
|
+
"ignore": [
|
|
51
|
+
"firebase.json",
|
|
52
|
+
"**/.*",
|
|
53
|
+
"**/node_modules/**"
|
|
54
|
+
],
|
|
55
|
+
"rewrites": [
|
|
56
|
+
{
|
|
57
|
+
"source": "**",
|
|
58
|
+
"destination": "/index.html"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"headers": {
|
|
62
|
+
"X-Content-Type-Options": "nosniff",
|
|
63
|
+
"X-XSS-Protection": "1; mode=block",
|
|
64
|
+
"X-Frame-Options": "deny",
|
|
65
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: leverege-sandbox-imagine-api.leverege.com *.mapbox.com *.firebaseio.com wss://*.firebaseio.com *.googleapis.com *.intercom.io wss://*.intercom.io maxcdn.bootstrapcdn.com *.intercomcdn.com *.gstatic.com;",
|
|
66
|
+
"Referrer-Policy":"no-referrer"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"site":"dev-olive-indoor-zoning",
|
|
71
|
+
"public": "dist",
|
|
72
|
+
"ignore": [
|
|
73
|
+
"firebase.json",
|
|
74
|
+
"**/.*",
|
|
75
|
+
"**/node_modules/**"
|
|
76
|
+
],
|
|
77
|
+
"rewrites": [
|
|
78
|
+
{
|
|
79
|
+
"source": "**",
|
|
80
|
+
"destination": "/index.html"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"headers": {
|
|
84
|
+
"X-Content-Type-Options": "nosniff",
|
|
85
|
+
"X-XSS-Protection": "1; mode=block",
|
|
86
|
+
"X-Frame-Options": "deny",
|
|
87
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: leverege-sandbox-imagine-api.leverege.com *.mapbox.com *.firebaseio.com wss://*.firebaseio.com *.googleapis.com *.intercom.io wss://*.intercom.io maxcdn.bootstrapcdn.com *.intercomcdn.com *.gstatic.com;",
|
|
88
|
+
"Referrer-Policy":"no-referrer"
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"site":"prd-indoor-zoning-ui",
|
|
93
|
+
"public": "dist",
|
|
94
|
+
"ignore": [
|
|
95
|
+
"firebase.json",
|
|
96
|
+
"**/.*",
|
|
97
|
+
"**/node_modules/**"
|
|
98
|
+
],
|
|
99
|
+
"rewrites": [
|
|
100
|
+
{
|
|
101
|
+
"source": "**",
|
|
102
|
+
"destination": "/index.html"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"headers": {
|
|
106
|
+
"X-Content-Type-Options": "nosniff",
|
|
107
|
+
"X-XSS-Protection": "1; mode=block",
|
|
108
|
+
"X-Frame-Options": "deny",
|
|
109
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: leverege-sandbox-imagine-api.leverege.com *.mapbox.com *.firebaseio.com wss://*.firebaseio.com *.googleapis.com *.intercom.io wss://*.intercom.io maxcdn.bootstrapcdn.com *.intercomcdn.com *.gstatic.com;",
|
|
110
|
+
"Referrer-Policy":"no-referrer"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"site":"prd-keys",
|
|
115
|
+
"public": "dist",
|
|
116
|
+
"ignore": [
|
|
117
|
+
"firebase.json",
|
|
118
|
+
"**/.*",
|
|
119
|
+
"**/node_modules/**"
|
|
120
|
+
],
|
|
121
|
+
"rewrites": [
|
|
122
|
+
{
|
|
123
|
+
"source": "**",
|
|
124
|
+
"destination": "/index.html"
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"headers": {
|
|
128
|
+
"X-Content-Type-Options": "nosniff",
|
|
129
|
+
"X-XSS-Protection": "1; mode=block",
|
|
130
|
+
"X-Frame-Options": "deny",
|
|
131
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: leverege-sandbox-imagine-api.leverege.com *.mapbox.com *.firebaseio.com wss://*.firebaseio.com *.googleapis.com *.intercom.io wss://*.intercom.io maxcdn.bootstrapcdn.com *.intercomcdn.com *.gstatic.com;",
|
|
132
|
+
"Referrer-Policy":"no-referrer"
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"site":"prd-olive-indoor-zoning-ui",
|
|
137
|
+
"public": "dist",
|
|
138
|
+
"ignore": [
|
|
139
|
+
"firebase.json",
|
|
140
|
+
"**/.*",
|
|
141
|
+
"**/node_modules/**"
|
|
142
|
+
],
|
|
143
|
+
"rewrites": [
|
|
144
|
+
{
|
|
145
|
+
"source": "**",
|
|
146
|
+
"destination": "/index.html"
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
"headers": {
|
|
150
|
+
"X-Content-Type-Options": "nosniff",
|
|
151
|
+
"X-XSS-Protection": "1; mode=block",
|
|
152
|
+
"X-Frame-Options": "deny",
|
|
153
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: leverege-sandbox-imagine-api.leverege.com *.mapbox.com *.firebaseio.com wss://*.firebaseio.com *.googleapis.com *.intercom.io wss://*.intercom.io maxcdn.bootstrapcdn.com *.intercomcdn.com *.gstatic.com;",
|
|
154
|
+
"Referrer-Policy":"no-referrer"
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"site":"stg-indoor-zoning-ui",
|
|
159
|
+
"public": "dist",
|
|
160
|
+
"ignore": [
|
|
161
|
+
"firebase.json",
|
|
162
|
+
"**/.*",
|
|
163
|
+
"**/node_modules/**"
|
|
164
|
+
],
|
|
165
|
+
"rewrites": [
|
|
166
|
+
{
|
|
167
|
+
"source": "**",
|
|
168
|
+
"destination": "/index.html"
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
"headers": {
|
|
172
|
+
"X-Content-Type-Options": "nosniff",
|
|
173
|
+
"X-XSS-Protection": "1; mode=block",
|
|
174
|
+
"X-Frame-Options": "deny",
|
|
175
|
+
"Content-Security-Policy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' data: blob: leverege-sandbox-imagine-api.leverege.com *.mapbox.com *.firebaseio.com wss://*.firebaseio.com *.googleapis.com *.intercom.io wss://*.intercom.io maxcdn.bootstrapcdn.com *.intercomcdn.com *.gstatic.com;",
|
|
176
|
+
"Referrer-Policy":"no-referrer"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
2
3
|
// https://github.com/google/zx
|
|
3
4
|
/* eslint-disable max-len */
|
|
4
5
|
"use strict";
|
|
5
6
|
|
|
6
7
|
var _enquirer = _interopRequireDefault(require("enquirer"));
|
|
8
|
+
var _ansiColors = _interopRequireDefault(require("ansi-colors"));
|
|
7
9
|
var _zx = require("zx");
|
|
8
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
11
|
const {
|
|
@@ -13,11 +15,27 @@ const {
|
|
|
13
15
|
// This will preserve coloration from spawned child processes
|
|
14
16
|
process.env.FORCE_COLORS = 3;
|
|
15
17
|
process.env.FORCE_COLOR = '1';
|
|
16
|
-
let TARGET
|
|
18
|
+
let TARGET;
|
|
19
|
+
let CHANNEL;
|
|
20
|
+
|
|
21
|
+
// A single unnamed parameter is assumed to be a deploy target.
|
|
22
|
+
// If named parameters exist, they may not be stored in argv,
|
|
23
|
+
// so don't use the length of argv to decide whether to look for them
|
|
24
|
+
if (_zx.argv._.length === 1) {
|
|
25
|
+
TARGET = _zx.argv._[0];
|
|
26
|
+
} else {
|
|
27
|
+
TARGET = _zx.argv.target;
|
|
28
|
+
if (_zx.argv.channelName) {
|
|
29
|
+
CHANNEL = {};
|
|
30
|
+
CHANNEL.name = _zx.argv.channelName;
|
|
31
|
+
CHANNEL.expiration = _zx.argv.channelExpiration ?? '7d';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const INTERACTIVE_MODE = !TARGET;
|
|
17
35
|
let exited = false;
|
|
18
36
|
const SECRETS_DIR = 'secrets';
|
|
19
37
|
const EXIT_EVENTS = ['SIGINT', 'exit', 'uncaughException', 'unhandledRejection'];
|
|
20
|
-
const [firebaserc, firebaseJson] = await Promise.all([_zx.fs.exists(_zx.path.join(process.cwd(), '.firebaserc')), _zx.fs.exists(_zx.path.join(process.cwd(), 'firebase.json'))]);
|
|
38
|
+
const [firebaserc, firebaseJson, git] = await Promise.all([_zx.fs.exists(_zx.path.join(process.cwd(), '.firebaserc')), _zx.fs.exists(_zx.path.join(process.cwd(), 'firebase.json')), _zx.fs.exists(_zx.path.join(process.cwd(), '.git/HEAD'))]);
|
|
21
39
|
if (!firebaserc) {
|
|
22
40
|
console.log(_zx.chalk.red('No .firebaserc file found. Make sure that you are executing firebaseDeploy from within a firebase project directory.'));
|
|
23
41
|
}
|
|
@@ -30,31 +48,87 @@ if (!firebaserc || !firebaseJson) {
|
|
|
30
48
|
const firebasercContent = JSON.parse(await _zx.fs.readFile(_zx.path.join(process.cwd(), '.firebaserc'), {
|
|
31
49
|
encoding: 'utf-8'
|
|
32
50
|
}));
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
|
|
52
|
+
// If in a git repo, fetch the name of the git branch to use as a default
|
|
53
|
+
// name in case a deployment channel is needed
|
|
54
|
+
let gitBranch;
|
|
55
|
+
if (git) {
|
|
56
|
+
const gitContent = (await _zx.fs.readFile(_zx.path.join(process.cwd(), '.git/HEAD'), {
|
|
57
|
+
encoding: 'utf-8'
|
|
58
|
+
}))?.split('/');
|
|
59
|
+
gitBranch = gitContent[gitContent?.length - 1]?.trimEnd('\n');
|
|
60
|
+
}
|
|
61
|
+
let maxPadding = 0;
|
|
62
|
+
const targets = Object.entries(firebasercContent.targets).reduce((prev, [projectId, config, production]) => {
|
|
63
|
+
Object.entries(config.hosting).forEach(([siteId, aliases, production]) => {
|
|
35
64
|
aliases.forEach(alias => {
|
|
65
|
+
maxPadding = Math.max(siteId.length, maxPadding);
|
|
36
66
|
prev[alias] = {
|
|
37
67
|
projectId,
|
|
38
68
|
siteId,
|
|
39
|
-
alias
|
|
69
|
+
alias,
|
|
70
|
+
production: config.production
|
|
40
71
|
};
|
|
41
72
|
});
|
|
42
73
|
});
|
|
43
74
|
return prev;
|
|
44
75
|
}, {});
|
|
45
|
-
if (
|
|
76
|
+
if (INTERACTIVE_MODE) {
|
|
46
77
|
const {
|
|
47
78
|
targetEnv
|
|
48
|
-
} = await prompt({
|
|
49
|
-
type: '
|
|
79
|
+
} = await prompt([{
|
|
80
|
+
type: 'select',
|
|
50
81
|
name: 'targetEnv',
|
|
51
82
|
message: 'To which environment would you like to deploy?',
|
|
52
|
-
choices: Object.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
83
|
+
choices: Object.values(targets).map(t => {
|
|
84
|
+
const productionLabel = t.production ? _ansiColors.default.bold.red('--PRODUCTION--') : '';
|
|
85
|
+
return {
|
|
86
|
+
message: `${_ansiColors.default.bold.cyan('Site: ')}${t.siteId.padEnd(maxPadding)} ${_ansiColors.default.bold.green('Project: ')}${t.projectId} ${productionLabel}`,
|
|
87
|
+
value: t.alias
|
|
88
|
+
};
|
|
89
|
+
})
|
|
90
|
+
}]);
|
|
57
91
|
TARGET = targets[targetEnv];
|
|
92
|
+
if (TARGET.production) {
|
|
93
|
+
const {
|
|
94
|
+
confirmProductionDeploy
|
|
95
|
+
} = await prompt([{
|
|
96
|
+
type: 'confirm',
|
|
97
|
+
name: 'confirmProductionDeploy',
|
|
98
|
+
message: `${_ansiColors.default.bold.red('WARNING: ')} This is a ${_ansiColors.default.bold.yellow('PRODUCTION')} environment. Are you sure you want to deploy here?`
|
|
99
|
+
}]);
|
|
100
|
+
if (!confirmProductionDeploy) {
|
|
101
|
+
console.log('Cancelling deployment...');
|
|
102
|
+
process.exit();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const {
|
|
106
|
+
useChannel
|
|
107
|
+
} = await prompt([{
|
|
108
|
+
type: 'confirm',
|
|
109
|
+
name: 'useChannel',
|
|
110
|
+
message: 'Do you want to deploy to a temporary preview channel?'
|
|
111
|
+
}]);
|
|
112
|
+
if (useChannel) {
|
|
113
|
+
const {
|
|
114
|
+
channelName,
|
|
115
|
+
channelExpiration
|
|
116
|
+
} = await prompt([{
|
|
117
|
+
type: 'input',
|
|
118
|
+
name: 'channelName',
|
|
119
|
+
message: 'To which channel would you like to deploy?',
|
|
120
|
+
initial: gitBranch ?? 'temp-deploy'
|
|
121
|
+
}, {
|
|
122
|
+
type: 'input',
|
|
123
|
+
name: 'channelExpiration',
|
|
124
|
+
message: 'When should the channel expire?',
|
|
125
|
+
initial: '7d'
|
|
126
|
+
}]);
|
|
127
|
+
CHANNEL = {
|
|
128
|
+
name: channelName,
|
|
129
|
+
expiration: channelExpiration
|
|
130
|
+
};
|
|
131
|
+
}
|
|
58
132
|
} else {
|
|
59
133
|
TARGET = targets[TARGET];
|
|
60
134
|
}
|
|
@@ -82,6 +156,26 @@ if (aliasFileExists) {
|
|
|
82
156
|
encoding: 'utf-8'
|
|
83
157
|
}));
|
|
84
158
|
}
|
|
159
|
+
if (INTERACTIVE_MODE) {
|
|
160
|
+
console.log(`\n\n\n${_ansiColors.default.bold.green('====== Deployment Summary ======')}`);
|
|
161
|
+
console.log(`${_ansiColors.default.blue('Firebase project:')} ${TARGET.projectId} ${TARGET.production ? _ansiColors.default.yellow('--PRODUCTION--') : ''}`);
|
|
162
|
+
console.log(`${_ansiColors.default.blue('Site ID:')} ${TARGET.siteId}`);
|
|
163
|
+
console.log(`${_ansiColors.default.blue('Channel Name:')} ${CHANNEL?.name ?? _ansiColors.default.italic.gray('(none)')}`);
|
|
164
|
+
console.log(`${_ansiColors.default.blue('Channel Expiration date:')} ${CHANNEL?.name ? CHANNEL.expiration ?? _ansiColors.default.italic.gray('(none)') : _ansiColors.default.italic.gray('(n/a)')}`);
|
|
165
|
+
console.log(`${_ansiColors.default.blue('Shared .env file:')} ${sharedFileExists ? `${SECRETS_DIR}/shared.env` : _ansiColors.default.italic.gray('(none)')}`);
|
|
166
|
+
console.log(`${_ansiColors.default.blue('Additional .env overrides:')} ${aliasFileExists ? `${SECRETS_DIR}/${TARGET.alias}.env` : `${SECRETS_DIR}/${TARGET.siteId}.env`}`);
|
|
167
|
+
const {
|
|
168
|
+
confirmSelections
|
|
169
|
+
} = await prompt([{
|
|
170
|
+
type: 'confirm',
|
|
171
|
+
name: 'confirmSelections',
|
|
172
|
+
message: 'Proceed with this deployment?'
|
|
173
|
+
}]);
|
|
174
|
+
if (!confirmSelections) {
|
|
175
|
+
console.log('Cancelling deployment...');
|
|
176
|
+
process.exit();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
85
179
|
const envFileContent = (await Promise.all(exec)).join('\n');
|
|
86
180
|
EXIT_EVENTS.forEach(event => {
|
|
87
181
|
process.on(event, () => {
|
|
@@ -93,7 +187,8 @@ EXIT_EVENTS.forEach(event => {
|
|
|
93
187
|
});
|
|
94
188
|
await _zx.fs.writeFile(_zx.path.join(process.cwd(), '.env.temp'), envFileContent);
|
|
95
189
|
try {
|
|
96
|
-
|
|
190
|
+
const deployType = CHANNEL ? `hosting:channel:deploy ${CHANNEL.name} ${CHANNEL.expiration ? `--expires ${CHANNEL.expiration}` : ''}` : 'deploy';
|
|
191
|
+
await (0, _zx.$)`npm run clean && DOTENV_CONFIG_PATH=${_zx.path.join(process.cwd(), '.env.temp')} npm run build && firebase use ${TARGET.projectId} && firebase ${deployType} --only hosting:${TARGET.siteId}`;
|
|
97
192
|
} catch (err) {
|
|
98
193
|
console.error(err);
|
|
99
194
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
2
3
|
// https://github.com/google/zx
|
|
3
4
|
/* eslint-disable max-len */
|
|
4
5
|
"use strict";
|
|
5
6
|
|
|
6
7
|
var _enquirer = _interopRequireDefault(require("enquirer"));
|
|
8
|
+
var _ansiColors = _interopRequireDefault(require("ansi-colors"));
|
|
7
9
|
var _zx = require("zx");
|
|
8
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
9
11
|
const {
|
|
@@ -13,11 +15,27 @@ const {
|
|
|
13
15
|
// This will preserve coloration from spawned child processes
|
|
14
16
|
process.env.FORCE_COLORS = 3;
|
|
15
17
|
process.env.FORCE_COLOR = '1';
|
|
16
|
-
let TARGET
|
|
18
|
+
let TARGET;
|
|
19
|
+
let CHANNEL;
|
|
20
|
+
|
|
21
|
+
// A single unnamed parameter is assumed to be a deploy target.
|
|
22
|
+
// If named parameters exist, they may not be stored in argv,
|
|
23
|
+
// so don't use the length of argv to decide whether to look for them
|
|
24
|
+
if (_zx.argv._.length === 1) {
|
|
25
|
+
TARGET = _zx.argv._[0];
|
|
26
|
+
} else {
|
|
27
|
+
TARGET = _zx.argv.target;
|
|
28
|
+
if (_zx.argv.channelName) {
|
|
29
|
+
CHANNEL = {};
|
|
30
|
+
CHANNEL.name = _zx.argv.channelName;
|
|
31
|
+
CHANNEL.expiration = _zx.argv.channelExpiration ?? '7d';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const INTERACTIVE_MODE = !TARGET;
|
|
17
35
|
let exited = false;
|
|
18
36
|
const SECRETS_DIR = 'secrets';
|
|
19
37
|
const EXIT_EVENTS = ['SIGINT', 'exit', 'uncaughException', 'unhandledRejection'];
|
|
20
|
-
const [firebaserc, firebaseJson] = await Promise.all([_zx.fs.exists(_zx.path.join(process.cwd(), '.firebaserc')), _zx.fs.exists(_zx.path.join(process.cwd(), 'firebase.json'))]);
|
|
38
|
+
const [firebaserc, firebaseJson, git] = await Promise.all([_zx.fs.exists(_zx.path.join(process.cwd(), '.firebaserc')), _zx.fs.exists(_zx.path.join(process.cwd(), 'firebase.json')), _zx.fs.exists(_zx.path.join(process.cwd(), '.git/HEAD'))]);
|
|
21
39
|
if (!firebaserc) {
|
|
22
40
|
console.log(_zx.chalk.red('No .firebaserc file found. Make sure that you are executing firebaseDeploy from within a firebase project directory.'));
|
|
23
41
|
}
|
|
@@ -30,31 +48,87 @@ if (!firebaserc || !firebaseJson) {
|
|
|
30
48
|
const firebasercContent = JSON.parse(await _zx.fs.readFile(_zx.path.join(process.cwd(), '.firebaserc'), {
|
|
31
49
|
encoding: 'utf-8'
|
|
32
50
|
}));
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
|
|
52
|
+
// If in a git repo, fetch the name of the git branch to use as a default
|
|
53
|
+
// name in case a deployment channel is needed
|
|
54
|
+
let gitBranch;
|
|
55
|
+
if (git) {
|
|
56
|
+
const gitContent = (await _zx.fs.readFile(_zx.path.join(process.cwd(), '.git/HEAD'), {
|
|
57
|
+
encoding: 'utf-8'
|
|
58
|
+
}))?.split('/');
|
|
59
|
+
gitBranch = gitContent[gitContent?.length - 1]?.trimEnd('\n');
|
|
60
|
+
}
|
|
61
|
+
let maxPadding = 0;
|
|
62
|
+
const targets = Object.entries(firebasercContent.targets).reduce((prev, [projectId, config, production]) => {
|
|
63
|
+
Object.entries(config.hosting).forEach(([siteId, aliases, production]) => {
|
|
35
64
|
aliases.forEach(alias => {
|
|
65
|
+
maxPadding = Math.max(siteId.length, maxPadding);
|
|
36
66
|
prev[alias] = {
|
|
37
67
|
projectId,
|
|
38
68
|
siteId,
|
|
39
|
-
alias
|
|
69
|
+
alias,
|
|
70
|
+
production: config.production
|
|
40
71
|
};
|
|
41
72
|
});
|
|
42
73
|
});
|
|
43
74
|
return prev;
|
|
44
75
|
}, {});
|
|
45
|
-
if (
|
|
76
|
+
if (INTERACTIVE_MODE) {
|
|
46
77
|
const {
|
|
47
78
|
targetEnv
|
|
48
|
-
} = await prompt({
|
|
49
|
-
type: '
|
|
79
|
+
} = await prompt([{
|
|
80
|
+
type: 'select',
|
|
50
81
|
name: 'targetEnv',
|
|
51
82
|
message: 'To which environment would you like to deploy?',
|
|
52
|
-
choices: Object.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
83
|
+
choices: Object.values(targets).map(t => {
|
|
84
|
+
const productionLabel = t.production ? _ansiColors.default.bold.red('--PRODUCTION--') : '';
|
|
85
|
+
return {
|
|
86
|
+
message: `${_ansiColors.default.bold.cyan('Site: ')}${t.siteId.padEnd(maxPadding)} ${_ansiColors.default.bold.green('Project: ')}${t.projectId} ${productionLabel}`,
|
|
87
|
+
value: t.alias
|
|
88
|
+
};
|
|
89
|
+
})
|
|
90
|
+
}]);
|
|
57
91
|
TARGET = targets[targetEnv];
|
|
92
|
+
if (TARGET.production) {
|
|
93
|
+
const {
|
|
94
|
+
confirmProductionDeploy
|
|
95
|
+
} = await prompt([{
|
|
96
|
+
type: 'confirm',
|
|
97
|
+
name: 'confirmProductionDeploy',
|
|
98
|
+
message: `${_ansiColors.default.bold.red('WARNING: ')} This is a ${_ansiColors.default.bold.yellow('PRODUCTION')} environment. Are you sure you want to deploy here?`
|
|
99
|
+
}]);
|
|
100
|
+
if (!confirmProductionDeploy) {
|
|
101
|
+
console.log('Cancelling deployment...');
|
|
102
|
+
process.exit();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const {
|
|
106
|
+
useChannel
|
|
107
|
+
} = await prompt([{
|
|
108
|
+
type: 'confirm',
|
|
109
|
+
name: 'useChannel',
|
|
110
|
+
message: 'Do you want to deploy to a temporary preview channel?'
|
|
111
|
+
}]);
|
|
112
|
+
if (useChannel) {
|
|
113
|
+
const {
|
|
114
|
+
channelName,
|
|
115
|
+
channelExpiration
|
|
116
|
+
} = await prompt([{
|
|
117
|
+
type: 'input',
|
|
118
|
+
name: 'channelName',
|
|
119
|
+
message: 'To which channel would you like to deploy?',
|
|
120
|
+
initial: gitBranch ?? 'temp-deploy'
|
|
121
|
+
}, {
|
|
122
|
+
type: 'input',
|
|
123
|
+
name: 'channelExpiration',
|
|
124
|
+
message: 'When should the channel expire?',
|
|
125
|
+
initial: '7d'
|
|
126
|
+
}]);
|
|
127
|
+
CHANNEL = {
|
|
128
|
+
name: channelName,
|
|
129
|
+
expiration: channelExpiration
|
|
130
|
+
};
|
|
131
|
+
}
|
|
58
132
|
} else {
|
|
59
133
|
TARGET = targets[TARGET];
|
|
60
134
|
}
|
|
@@ -82,6 +156,26 @@ if (aliasFileExists) {
|
|
|
82
156
|
encoding: 'utf-8'
|
|
83
157
|
}));
|
|
84
158
|
}
|
|
159
|
+
if (INTERACTIVE_MODE) {
|
|
160
|
+
console.log(`\n\n\n${_ansiColors.default.bold.green('====== Deployment Summary ======')}`);
|
|
161
|
+
console.log(`${_ansiColors.default.blue('Firebase project:')} ${TARGET.projectId} ${TARGET.production ? _ansiColors.default.yellow('--PRODUCTION--') : ''}`);
|
|
162
|
+
console.log(`${_ansiColors.default.blue('Site ID:')} ${TARGET.siteId}`);
|
|
163
|
+
console.log(`${_ansiColors.default.blue('Channel Name:')} ${CHANNEL?.name ?? _ansiColors.default.italic.gray('(none)')}`);
|
|
164
|
+
console.log(`${_ansiColors.default.blue('Channel Expiration date:')} ${CHANNEL?.name ? CHANNEL.expiration ?? _ansiColors.default.italic.gray('(none)') : _ansiColors.default.italic.gray('(n/a)')}`);
|
|
165
|
+
console.log(`${_ansiColors.default.blue('Shared .env file:')} ${sharedFileExists ? `${SECRETS_DIR}/shared.env` : _ansiColors.default.italic.gray('(none)')}`);
|
|
166
|
+
console.log(`${_ansiColors.default.blue('Additional .env overrides:')} ${aliasFileExists ? `${SECRETS_DIR}/${TARGET.alias}.env` : `${SECRETS_DIR}/${TARGET.siteId}.env`}`);
|
|
167
|
+
const {
|
|
168
|
+
confirmSelections
|
|
169
|
+
} = await prompt([{
|
|
170
|
+
type: 'confirm',
|
|
171
|
+
name: 'confirmSelections',
|
|
172
|
+
message: 'Proceed with this deployment?'
|
|
173
|
+
}]);
|
|
174
|
+
if (!confirmSelections) {
|
|
175
|
+
console.log('Cancelling deployment...');
|
|
176
|
+
process.exit();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
85
179
|
const envFileContent = (await Promise.all(exec)).join('\n');
|
|
86
180
|
EXIT_EVENTS.forEach(event => {
|
|
87
181
|
process.on(event, () => {
|
|
@@ -93,7 +187,8 @@ EXIT_EVENTS.forEach(event => {
|
|
|
93
187
|
});
|
|
94
188
|
await _zx.fs.writeFile(_zx.path.join(process.cwd(), '.env.temp'), envFileContent);
|
|
95
189
|
try {
|
|
96
|
-
|
|
190
|
+
const deployType = CHANNEL ? `hosting:channel:deploy ${CHANNEL.name} ${CHANNEL.expiration ? `--expires ${CHANNEL.expiration}` : ''}` : 'deploy';
|
|
191
|
+
await (0, _zx.$)`npm run clean && DOTENV_CONFIG_PATH=${_zx.path.join(process.cwd(), '.env.temp')} npm run build && firebase use ${TARGET.projectId} && firebase ${deployType} --only hosting:${TARGET.siteId}`;
|
|
97
192
|
} catch (err) {
|
|
98
193
|
console.error(err);
|
|
99
194
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leverege/build-tools",
|
|
3
|
-
"version": "2.21.
|
|
3
|
+
"version": "2.21.9-nick.2",
|
|
4
4
|
"description": "A collection of build / support tools for Leverege developers",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"author": "Leverege Devs",
|
|
50
50
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
51
51
|
"dependencies": {
|
|
52
|
+
"ansi-colors": "^4.1.3",
|
|
52
53
|
"chalk": "^4.1.2",
|
|
53
54
|
"command-line-args": "^5.2.1",
|
|
54
55
|
"command-line-usage": "^6.1.3",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
IMAGINE_HOST=https://leverege-sandbox-imagine-api.leverege.com
|
|
2
|
+
RECOVR_HOST=https://dev-recovr-notify.leverege.com
|
|
3
|
+
# RECOVR_HOST=http://localhost:8296
|
|
4
|
+
SYSTEM_ID=0UTmPFvRHXYLMlT4Kl2z1K
|
|
5
|
+
PROJECT_ID=08HBeHEYGxu5Bg4TCCnAAV
|
|
6
|
+
VEHICLE_NETWORK_ID='dev-dealership-vehicles'
|
|
7
|
+
CONSUMER_VEHICLE_NETWORK_ID='dev-customer-vehicles'
|
|
8
|
+
LOCATOR_NETWORK_ID='dev-recovr-tracker'
|
|
9
|
+
BEACON_NETWORK_ID='dev-dealership-beacons'
|
|
10
|
+
SALE_LOCATION_PARENT_PATH=sales
|
|
11
|
+
CONSUMER_LOCATION_ID=1KceIcZlVWrOBvCzsEXYud
|
|
12
|
+
userManagementUiName='obd'
|
|
13
|
+
IS_DEV=true
|
package/secrets/dev.env
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
IMAGINE_HOST=https://leverege-sandbox-imagine-api.leverege.com
|
|
2
|
+
RECOVR_HOST=https://dev-recovr-notify.leverege.com
|
|
3
|
+
# RECOVR_HOST=http://localhost:8296
|
|
4
|
+
SYSTEM_ID=0UTmPFvRHXYLMlT4Kl2z1K
|
|
5
|
+
PROJECT_ID=08HBeHEYGxu5Bg4TCCnAAV
|
|
6
|
+
VEHICLE_NETWORK_ID='dev-dealership-vehicles'
|
|
7
|
+
CONSUMER_VEHICLE_NETWORK_ID='dev-customer-vehicles'
|
|
8
|
+
LOCATOR_NETWORK_ID='dev-recovr-tracker'
|
|
9
|
+
BEACON_NETWORK_ID='dev-dealership-beacons'
|
|
10
|
+
SALE_LOCATION_PARENT_PATH=sales
|
|
11
|
+
CONSUMER_LOCATION_ID=1KceIcZlVWrOBvCzsEXYud
|
|
12
|
+
IS_DEV=true
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
IMAGINE_HOST=https://prd-recovr-auto-imagine-api.leverege.com
|
|
2
|
+
RECOVR_HOST=https://recovr-auto-notify.leverege.com
|
|
3
|
+
SYSTEM_ID=2ExK7rl76meCVCCctjOJEY
|
|
4
|
+
PROJECT_ID=1Je8Y7dNlfthv7ixV8oEfZ
|
|
5
|
+
VEHICLE_NETWORK_ID='prd-auto-vehicles'
|
|
6
|
+
CONSUMER_VEHICLE_NETWORK_ID='prd-customer-vehicles'
|
|
7
|
+
BEACON_NETWORK_ID='prd-auto-beacons'
|
|
8
|
+
GOOGLE_ANALYTICS_TRACKER_ID='G-LBTT0JT9V6'
|
|
9
|
+
SALE_LOCATION_PARENT_PATH=location
|
|
10
|
+
CONSUMER_LOCATION_ID=26OsDlsRqBTIOxMjyHg9S5
|
|
11
|
+
userManagementUiName='obd'
|
|
12
|
+
IS_DEV=true
|
package/secrets/prd.env
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
IMAGINE_HOST=https://prd-recovr-auto-imagine-api.leverege.com
|
|
2
|
+
RECOVR_HOST=https://recovr-auto-notify.leverege.com
|
|
3
|
+
SYSTEM_ID=2ExK7rl76meCVCCctjOJEY
|
|
4
|
+
PROJECT_ID=1Je8Y7dNlfthv7ixV8oEfZ
|
|
5
|
+
VEHICLE_NETWORK_ID='prd-auto-vehicles'
|
|
6
|
+
CONSUMER_VEHICLE_NETWORK_ID='prd-customer-vehicles'
|
|
7
|
+
BEACON_NETWORK_ID='prd-auto-beacons'
|
|
8
|
+
GOOGLE_ANALYTICS_TRACKER_ID='G-LBTT0JT9V6'
|
|
9
|
+
SALE_LOCATION_PARENT_PATH=location
|
|
10
|
+
CONSUMER_LOCATION_ID=26OsDlsRqBTIOxMjyHg9S5
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
THEFT_RECOVERY_URL='theft.recovermycar.com'
|
|
2
|
+
MAPBOX_APIKEY=pk.eyJ1IjoibGV2ZXJlZ2UiLCJhIjoiY2p1Y3E0cWpkMG15azQzbnFzaDY2dmhiMSJ9.7N25h5jsjO2Aq_YmiLrAJw
|
|
3
|
+
APPEARANCE_PROJECT_ID=7b2GTbmsZj3f5VdFpjGM8O
|
|
4
|
+
INTERCOM_APP_ID='ec0qbuwi'
|
|
5
|
+
LOCATOR_ALIAS_KEY='serialNumber'
|
|
6
|
+
RECOVR_BILLING_MODULE='recovrBilling'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
IMAGINE_HOST=https://stg-recovr-auto-imagine-api.leverege.com
|
|
2
|
+
# RECOVR_HOST=http://localhost:8296
|
|
3
|
+
SYSTEM_ID=6CxONnaSOnbGFBS5gLnZWl
|
|
4
|
+
PROJECT_ID=3vo2u8m9GEXPaQgMnJ45rh
|
|
5
|
+
VEHICLE_NETWORK_ID='stg-auto-vehicles'
|
|
6
|
+
CONSUMER_VEHICLE_NETWORK_ID='stg-customer-vehicles'
|
|
7
|
+
BEACON_NETWORK_ID='stg-auto-beacons'
|
|
8
|
+
CONSUMER_LOCATION_ID=1SRDkIuPWDpiAy4dsuy0JT
|
|
9
|
+
userManagementUiName='obd'
|
|
10
|
+
IS_DEV=false
|
package/secrets/stg.env
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
IMAGINE_HOST=https://stg-recovr-auto-imagine-api.leverege.com
|
|
2
|
+
# RECOVR_HOST=http://localhost:8296
|
|
3
|
+
SYSTEM_ID=6CxONnaSOnbGFBS5gLnZWl
|
|
4
|
+
PROJECT_ID=3vo2u8m9GEXPaQgMnJ45rh
|
|
5
|
+
VEHICLE_NETWORK_ID='stg-auto-vehicles'
|
|
6
|
+
CONSUMER_VEHICLE_NETWORK_ID='stg-customer-vehicles'
|
|
7
|
+
BEACON_NETWORK_ID='stg-auto-beacons'
|
|
8
|
+
CONSUMER_LOCATION_ID=1SRDkIuPWDpiAy4dsuy0JT
|
|
9
|
+
IS_DEV=false
|
package/src/firebaseDeploy.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
2
3
|
// https://github.com/google/zx
|
|
3
4
|
/* eslint-disable max-len */
|
|
4
5
|
import pkg from 'enquirer'
|
|
6
|
+
import colors from 'ansi-colors'
|
|
5
7
|
import { $, fs, argv, path, chalk } from 'zx'
|
|
6
8
|
|
|
7
9
|
const { prompt } = pkg
|
|
@@ -10,7 +12,26 @@ const { prompt } = pkg
|
|
|
10
12
|
process.env.FORCE_COLORS = 3
|
|
11
13
|
process.env.FORCE_COLOR = '1'
|
|
12
14
|
|
|
13
|
-
let TARGET
|
|
15
|
+
let TARGET
|
|
16
|
+
let CHANNEL
|
|
17
|
+
|
|
18
|
+
// A single unnamed parameter is assumed to be a deploy target.
|
|
19
|
+
// If named parameters exist, they may not be stored in argv,
|
|
20
|
+
// so don't use the length of argv to decide whether to look for them
|
|
21
|
+
if ( argv._.length === 1 ) {
|
|
22
|
+
TARGET = argv._[0]
|
|
23
|
+
} else {
|
|
24
|
+
TARGET = argv.target
|
|
25
|
+
|
|
26
|
+
if ( argv.channelName ) {
|
|
27
|
+
CHANNEL = {}
|
|
28
|
+
CHANNEL.name = argv.channelName
|
|
29
|
+
CHANNEL.expiration = argv.channelExpiration ?? '7d'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const INTERACTIVE_MODE = !TARGET
|
|
34
|
+
|
|
14
35
|
let exited = false
|
|
15
36
|
|
|
16
37
|
const SECRETS_DIR = 'secrets'
|
|
@@ -18,10 +39,12 @@ const EXIT_EVENTS = [ 'SIGINT', 'exit', 'uncaughException', 'unhandledRejection'
|
|
|
18
39
|
|
|
19
40
|
const [
|
|
20
41
|
firebaserc,
|
|
21
|
-
firebaseJson
|
|
42
|
+
firebaseJson,
|
|
43
|
+
git
|
|
22
44
|
] = await Promise.all( [
|
|
23
45
|
fs.exists( path.join( process.cwd(), '.firebaserc' ) ),
|
|
24
|
-
fs.exists( path.join( process.cwd(), 'firebase.json' ) )
|
|
46
|
+
fs.exists( path.join( process.cwd(), 'firebase.json' ) ),
|
|
47
|
+
fs.exists( path.join( process.cwd(), '.git/HEAD' ) )
|
|
25
48
|
] )
|
|
26
49
|
|
|
27
50
|
if ( !firebaserc ) {
|
|
@@ -38,17 +61,29 @@ if ( !firebaserc || !firebaseJson ) {
|
|
|
38
61
|
|
|
39
62
|
const firebasercContent = JSON.parse( await fs.readFile( path.join( process.cwd(), '.firebaserc' ), { encoding : 'utf-8' } ) )
|
|
40
63
|
|
|
64
|
+
// If in a git repo, fetch the name of the git branch to use as a default
|
|
65
|
+
// name in case a deployment channel is needed
|
|
66
|
+
let gitBranch
|
|
67
|
+
if ( git ) {
|
|
68
|
+
const gitContent = ( await fs.readFile( path.join( process.cwd(), '.git/HEAD' ), { encoding : 'utf-8' } ) )?.split( '/' )
|
|
69
|
+
gitBranch = gitContent[gitContent?.length - 1]?.trimEnd( '\n' )
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let maxPadding = 0
|
|
73
|
+
|
|
41
74
|
const targets = Object
|
|
42
75
|
.entries( firebasercContent.targets )
|
|
43
|
-
.reduce( ( prev, [ projectId, config ] ) => {
|
|
76
|
+
.reduce( ( prev, [ projectId, config, production ] ) => {
|
|
44
77
|
Object
|
|
45
78
|
.entries( config.hosting )
|
|
46
|
-
.forEach( ( [ siteId, aliases ] ) => {
|
|
79
|
+
.forEach( ( [ siteId, aliases, production ] ) => {
|
|
47
80
|
aliases.forEach( ( alias ) => {
|
|
81
|
+
maxPadding = Math.max( siteId.length, maxPadding )
|
|
48
82
|
prev[alias] = {
|
|
49
83
|
projectId,
|
|
50
84
|
siteId,
|
|
51
|
-
alias
|
|
85
|
+
alias,
|
|
86
|
+
production : config.production
|
|
52
87
|
}
|
|
53
88
|
} )
|
|
54
89
|
} )
|
|
@@ -56,15 +91,53 @@ const targets = Object
|
|
|
56
91
|
return prev
|
|
57
92
|
}, {} )
|
|
58
93
|
|
|
59
|
-
if (
|
|
60
|
-
const { targetEnv } = await prompt( {
|
|
61
|
-
type : '
|
|
94
|
+
if ( INTERACTIVE_MODE ) {
|
|
95
|
+
const { targetEnv } = await prompt( [ {
|
|
96
|
+
type : 'select',
|
|
62
97
|
name : 'targetEnv',
|
|
63
98
|
message : 'To which environment would you like to deploy?',
|
|
64
|
-
choices : Object.
|
|
65
|
-
|
|
99
|
+
choices : Object.values( targets ).map( ( t ) => {
|
|
100
|
+
const productionLabel = t.production ? colors.bold.red( '--PRODUCTION--' ) : ''
|
|
101
|
+
return { message : `${colors.bold.cyan( 'Site: ' )}${t.siteId.padEnd( maxPadding )} ${colors.bold.green( 'Project: ' )}${t.projectId} ${productionLabel}`, value : t.alias }
|
|
102
|
+
} )
|
|
103
|
+
} ] )
|
|
66
104
|
|
|
67
105
|
TARGET = targets[targetEnv]
|
|
106
|
+
|
|
107
|
+
if ( TARGET.production ) {
|
|
108
|
+
const { confirmProductionDeploy } = await prompt( [ {
|
|
109
|
+
type : 'confirm',
|
|
110
|
+
name : 'confirmProductionDeploy',
|
|
111
|
+
message : `${colors.bold.red( 'WARNING: ' )} This is a ${colors.bold.yellow( 'PRODUCTION' )} environment. Are you sure you want to deploy here?`
|
|
112
|
+
} ] )
|
|
113
|
+
if ( !confirmProductionDeploy ) {
|
|
114
|
+
console.log( 'Cancelling deployment...' )
|
|
115
|
+
process.exit()
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const { useChannel } = await prompt( [ {
|
|
120
|
+
type : 'confirm',
|
|
121
|
+
name : 'useChannel',
|
|
122
|
+
message : 'Do you want to deploy to a temporary preview channel?'
|
|
123
|
+
} ] )
|
|
124
|
+
|
|
125
|
+
if ( useChannel ) {
|
|
126
|
+
const { channelName, channelExpiration } = await prompt( [ {
|
|
127
|
+
type : 'input',
|
|
128
|
+
name : 'channelName',
|
|
129
|
+
message : 'To which channel would you like to deploy?',
|
|
130
|
+
initial : gitBranch ?? 'temp-deploy'
|
|
131
|
+
}, {
|
|
132
|
+
type : 'input',
|
|
133
|
+
name : 'channelExpiration',
|
|
134
|
+
message : 'When should the channel expire?',
|
|
135
|
+
initial : '7d'
|
|
136
|
+
} ] )
|
|
137
|
+
|
|
138
|
+
CHANNEL = { name : channelName, expiration : channelExpiration }
|
|
139
|
+
}
|
|
140
|
+
|
|
68
141
|
} else {
|
|
69
142
|
TARGET = targets[TARGET]
|
|
70
143
|
}
|
|
@@ -97,6 +170,26 @@ if ( aliasFileExists ) {
|
|
|
97
170
|
exec.push( fs.readFile( path.join( process.cwd(), SECRETS_DIR, `${TARGET.siteId}.env` ), { encoding : 'utf-8' } ) )
|
|
98
171
|
}
|
|
99
172
|
|
|
173
|
+
if ( INTERACTIVE_MODE ) {
|
|
174
|
+
console.log( `\n\n\n${colors.bold.green( '====== Deployment Summary ======' )}` )
|
|
175
|
+
console.log( `${colors.blue( 'Firebase project:' )} ${TARGET.projectId} ${TARGET.production ? colors.yellow( '--PRODUCTION--' ) : ''}` )
|
|
176
|
+
console.log( `${colors.blue( 'Site ID:' )} ${TARGET.siteId}` )
|
|
177
|
+
console.log( `${colors.blue( 'Channel Name:' )} ${CHANNEL?.name ?? colors.italic.gray( '(none)' )}` )
|
|
178
|
+
console.log( `${colors.blue( 'Channel Expiration date:' )} ${CHANNEL?.name ? CHANNEL.expiration ?? colors.italic.gray( '(none)' ) : colors.italic.gray( '(n/a)' )}` )
|
|
179
|
+
console.log( `${colors.blue( 'Shared .env file:' )} ${sharedFileExists ? `${SECRETS_DIR}/shared.env` : colors.italic.gray( '(none)' )}` )
|
|
180
|
+
console.log( `${colors.blue( 'Additional .env overrides:' )} ${aliasFileExists ? `${SECRETS_DIR}/${TARGET.alias}.env` : `${SECRETS_DIR}/${TARGET.siteId}.env`}` )
|
|
181
|
+
|
|
182
|
+
const { confirmSelections } = await prompt( [ {
|
|
183
|
+
type : 'confirm',
|
|
184
|
+
name : 'confirmSelections',
|
|
185
|
+
message : 'Proceed with this deployment?'
|
|
186
|
+
} ] )
|
|
187
|
+
|
|
188
|
+
if ( !confirmSelections ) {
|
|
189
|
+
console.log( 'Cancelling deployment...' )
|
|
190
|
+
process.exit()
|
|
191
|
+
}
|
|
192
|
+
}
|
|
100
193
|
const envFileContent = ( await Promise.all( exec ) ).join( '\n' )
|
|
101
194
|
|
|
102
195
|
EXIT_EVENTS
|
|
@@ -112,7 +205,8 @@ EXIT_EVENTS
|
|
|
112
205
|
await fs.writeFile( path.join( process.cwd(), '.env.temp' ), envFileContent )
|
|
113
206
|
|
|
114
207
|
try {
|
|
115
|
-
|
|
208
|
+
const deployType = CHANNEL ? `hosting:channel:deploy ${CHANNEL.name} ${CHANNEL.expiration ? `--expires ${CHANNEL.expiration}` : ''}` : 'deploy'
|
|
209
|
+
await $`npm run clean && DOTENV_CONFIG_PATH=${path.join( process.cwd(), '.env.temp' )} npm run build && firebase use ${TARGET.projectId} && firebase ${deployType} --only hosting:${TARGET.siteId}`
|
|
116
210
|
} catch ( err ) {
|
|
117
211
|
console.error( err )
|
|
118
212
|
}
|