@leverege/build-tools 2.21.8 → 2.21.9-nick.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.firebaserc +47 -0
- package/.vscode/launch.json +18 -0
- package/firebase.json +180 -0
- package/lib/server/firebaseDeploy.js +87 -13
- package/lib/web/firebaseDeploy.js +87 -13
- package/package.json +2 -1
- package/src/firebaseDeploy.mjs +83 -11
package/.firebaserc
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-ui": [
|
|
28
|
+
"prd-indoor-zoning-ui"
|
|
29
|
+
],
|
|
30
|
+
"prd-olive-indoor-zoning-ui": [
|
|
31
|
+
"prd-olive-indoor-zoning-ui"
|
|
32
|
+
],
|
|
33
|
+
"prd-keys": [
|
|
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,26 @@ 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
|
+
}
|
|
17
34
|
let exited = false;
|
|
18
35
|
const SECRETS_DIR = 'secrets';
|
|
19
36
|
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'))]);
|
|
37
|
+
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
38
|
if (!firebaserc) {
|
|
22
39
|
console.log(_zx.chalk.red('No .firebaserc file found. Make sure that you are executing firebaseDeploy from within a firebase project directory.'));
|
|
23
40
|
}
|
|
@@ -30,13 +47,26 @@ if (!firebaserc || !firebaseJson) {
|
|
|
30
47
|
const firebasercContent = JSON.parse(await _zx.fs.readFile(_zx.path.join(process.cwd(), '.firebaserc'), {
|
|
31
48
|
encoding: 'utf-8'
|
|
32
49
|
}));
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
|
|
51
|
+
// If in a git repo, fetch the name of the git branch to use as a default
|
|
52
|
+
// name in case a deployment channel is needed
|
|
53
|
+
let gitBranch;
|
|
54
|
+
if (git) {
|
|
55
|
+
const gitContent = (await _zx.fs.readFile(_zx.path.join(process.cwd(), '.git/HEAD'), {
|
|
56
|
+
encoding: 'utf-8'
|
|
57
|
+
}))?.split('/');
|
|
58
|
+
gitBranch = gitContent[gitContent?.length - 1]?.trimEnd('\n');
|
|
59
|
+
}
|
|
60
|
+
let maxPadding = 0;
|
|
61
|
+
const targets = Object.entries(firebasercContent.targets).reduce((prev, [projectId, config, production]) => {
|
|
62
|
+
Object.entries(config.hosting).forEach(([siteId, aliases, production]) => {
|
|
35
63
|
aliases.forEach(alias => {
|
|
64
|
+
maxPadding = Math.max(siteId.length, maxPadding);
|
|
36
65
|
prev[alias] = {
|
|
37
66
|
projectId,
|
|
38
67
|
siteId,
|
|
39
|
-
alias
|
|
68
|
+
alias,
|
|
69
|
+
production: config.production
|
|
40
70
|
};
|
|
41
71
|
});
|
|
42
72
|
});
|
|
@@ -45,16 +75,59 @@ const targets = Object.entries(firebasercContent.targets).reduce((prev, [project
|
|
|
45
75
|
if (!TARGET) {
|
|
46
76
|
const {
|
|
47
77
|
targetEnv
|
|
48
|
-
} = await prompt({
|
|
49
|
-
type: '
|
|
78
|
+
} = await prompt([{
|
|
79
|
+
type: 'select',
|
|
50
80
|
name: 'targetEnv',
|
|
51
81
|
message: 'To which environment would you like to deploy?',
|
|
52
|
-
choices: Object.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
82
|
+
choices: Object.values(targets).map(t => {
|
|
83
|
+
const productionLabel = t.production ? _ansiColors.default.bold.red('--PRODUCTION--') : '';
|
|
84
|
+
return {
|
|
85
|
+
message: `${_ansiColors.default.bold.cyan('Site: ')}${t.siteId.padEnd(maxPadding)} ${_ansiColors.default.bold.green('Project: ')}${t.projectId} ${productionLabel}`,
|
|
86
|
+
value: t.siteId
|
|
87
|
+
};
|
|
88
|
+
})
|
|
89
|
+
}]);
|
|
57
90
|
TARGET = targets[targetEnv];
|
|
91
|
+
if (TARGET.production) {
|
|
92
|
+
const {
|
|
93
|
+
confirmProductionDeploy
|
|
94
|
+
} = await prompt([{
|
|
95
|
+
type: 'confirm',
|
|
96
|
+
name: 'confirmProductionDeploy',
|
|
97
|
+
message: `${_ansiColors.default.bold.red('WARNING: ')} This is a ${_ansiColors.default.bold.yellow('PRODUCTION')} deployment target. Are you sure you want to proceed?`
|
|
98
|
+
}]);
|
|
99
|
+
if (!confirmProductionDeploy) {
|
|
100
|
+
console.log('Cancelling deployment...');
|
|
101
|
+
process.exit();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const {
|
|
105
|
+
useChannel
|
|
106
|
+
} = await prompt([{
|
|
107
|
+
type: 'confirm',
|
|
108
|
+
name: 'useChannel',
|
|
109
|
+
message: 'Do you want to deploy to a temporary preview channel?'
|
|
110
|
+
}]);
|
|
111
|
+
if (useChannel) {
|
|
112
|
+
const {
|
|
113
|
+
channelName,
|
|
114
|
+
channelExpiration
|
|
115
|
+
} = await prompt([{
|
|
116
|
+
type: 'input',
|
|
117
|
+
name: 'channelName',
|
|
118
|
+
message: 'To which channel would you like to deploy?',
|
|
119
|
+
initial: gitBranch ?? 'temp-deploy'
|
|
120
|
+
}, {
|
|
121
|
+
type: 'input',
|
|
122
|
+
name: 'channelExpiration',
|
|
123
|
+
message: 'When should the channel expire?',
|
|
124
|
+
initial: '7d'
|
|
125
|
+
}]);
|
|
126
|
+
CHANNEL = {
|
|
127
|
+
name: channelName,
|
|
128
|
+
expiration: channelExpiration
|
|
129
|
+
};
|
|
130
|
+
}
|
|
58
131
|
} else {
|
|
59
132
|
TARGET = targets[TARGET];
|
|
60
133
|
}
|
|
@@ -93,7 +166,8 @@ EXIT_EVENTS.forEach(event => {
|
|
|
93
166
|
});
|
|
94
167
|
await _zx.fs.writeFile(_zx.path.join(process.cwd(), '.env.temp'), envFileContent);
|
|
95
168
|
try {
|
|
96
|
-
|
|
169
|
+
const deployType = CHANNEL ? `hosting:channel:deploy ${CHANNEL.name} --expires ${CHANNEL.expiration}` : 'deploy';
|
|
170
|
+
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
171
|
} catch (err) {
|
|
98
172
|
console.error(err);
|
|
99
173
|
}
|
|
@@ -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,26 @@ 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
|
+
}
|
|
17
34
|
let exited = false;
|
|
18
35
|
const SECRETS_DIR = 'secrets';
|
|
19
36
|
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'))]);
|
|
37
|
+
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
38
|
if (!firebaserc) {
|
|
22
39
|
console.log(_zx.chalk.red('No .firebaserc file found. Make sure that you are executing firebaseDeploy from within a firebase project directory.'));
|
|
23
40
|
}
|
|
@@ -30,13 +47,26 @@ if (!firebaserc || !firebaseJson) {
|
|
|
30
47
|
const firebasercContent = JSON.parse(await _zx.fs.readFile(_zx.path.join(process.cwd(), '.firebaserc'), {
|
|
31
48
|
encoding: 'utf-8'
|
|
32
49
|
}));
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
|
|
51
|
+
// If in a git repo, fetch the name of the git branch to use as a default
|
|
52
|
+
// name in case a deployment channel is needed
|
|
53
|
+
let gitBranch;
|
|
54
|
+
if (git) {
|
|
55
|
+
const gitContent = (await _zx.fs.readFile(_zx.path.join(process.cwd(), '.git/HEAD'), {
|
|
56
|
+
encoding: 'utf-8'
|
|
57
|
+
}))?.split('/');
|
|
58
|
+
gitBranch = gitContent[gitContent?.length - 1]?.trimEnd('\n');
|
|
59
|
+
}
|
|
60
|
+
let maxPadding = 0;
|
|
61
|
+
const targets = Object.entries(firebasercContent.targets).reduce((prev, [projectId, config, production]) => {
|
|
62
|
+
Object.entries(config.hosting).forEach(([siteId, aliases, production]) => {
|
|
35
63
|
aliases.forEach(alias => {
|
|
64
|
+
maxPadding = Math.max(siteId.length, maxPadding);
|
|
36
65
|
prev[alias] = {
|
|
37
66
|
projectId,
|
|
38
67
|
siteId,
|
|
39
|
-
alias
|
|
68
|
+
alias,
|
|
69
|
+
production: config.production
|
|
40
70
|
};
|
|
41
71
|
});
|
|
42
72
|
});
|
|
@@ -45,16 +75,59 @@ const targets = Object.entries(firebasercContent.targets).reduce((prev, [project
|
|
|
45
75
|
if (!TARGET) {
|
|
46
76
|
const {
|
|
47
77
|
targetEnv
|
|
48
|
-
} = await prompt({
|
|
49
|
-
type: '
|
|
78
|
+
} = await prompt([{
|
|
79
|
+
type: 'select',
|
|
50
80
|
name: 'targetEnv',
|
|
51
81
|
message: 'To which environment would you like to deploy?',
|
|
52
|
-
choices: Object.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
82
|
+
choices: Object.values(targets).map(t => {
|
|
83
|
+
const productionLabel = t.production ? _ansiColors.default.bold.red('--PRODUCTION--') : '';
|
|
84
|
+
return {
|
|
85
|
+
message: `${_ansiColors.default.bold.cyan('Site: ')}${t.siteId.padEnd(maxPadding)} ${_ansiColors.default.bold.green('Project: ')}${t.projectId} ${productionLabel}`,
|
|
86
|
+
value: t.siteId
|
|
87
|
+
};
|
|
88
|
+
})
|
|
89
|
+
}]);
|
|
57
90
|
TARGET = targets[targetEnv];
|
|
91
|
+
if (TARGET.production) {
|
|
92
|
+
const {
|
|
93
|
+
confirmProductionDeploy
|
|
94
|
+
} = await prompt([{
|
|
95
|
+
type: 'confirm',
|
|
96
|
+
name: 'confirmProductionDeploy',
|
|
97
|
+
message: `${_ansiColors.default.bold.red('WARNING: ')} This is a ${_ansiColors.default.bold.yellow('PRODUCTION')} deployment target. Are you sure you want to proceed?`
|
|
98
|
+
}]);
|
|
99
|
+
if (!confirmProductionDeploy) {
|
|
100
|
+
console.log('Cancelling deployment...');
|
|
101
|
+
process.exit();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const {
|
|
105
|
+
useChannel
|
|
106
|
+
} = await prompt([{
|
|
107
|
+
type: 'confirm',
|
|
108
|
+
name: 'useChannel',
|
|
109
|
+
message: 'Do you want to deploy to a temporary preview channel?'
|
|
110
|
+
}]);
|
|
111
|
+
if (useChannel) {
|
|
112
|
+
const {
|
|
113
|
+
channelName,
|
|
114
|
+
channelExpiration
|
|
115
|
+
} = await prompt([{
|
|
116
|
+
type: 'input',
|
|
117
|
+
name: 'channelName',
|
|
118
|
+
message: 'To which channel would you like to deploy?',
|
|
119
|
+
initial: gitBranch ?? 'temp-deploy'
|
|
120
|
+
}, {
|
|
121
|
+
type: 'input',
|
|
122
|
+
name: 'channelExpiration',
|
|
123
|
+
message: 'When should the channel expire?',
|
|
124
|
+
initial: '7d'
|
|
125
|
+
}]);
|
|
126
|
+
CHANNEL = {
|
|
127
|
+
name: channelName,
|
|
128
|
+
expiration: channelExpiration
|
|
129
|
+
};
|
|
130
|
+
}
|
|
58
131
|
} else {
|
|
59
132
|
TARGET = targets[TARGET];
|
|
60
133
|
}
|
|
@@ -93,7 +166,8 @@ EXIT_EVENTS.forEach(event => {
|
|
|
93
166
|
});
|
|
94
167
|
await _zx.fs.writeFile(_zx.path.join(process.cwd(), '.env.temp'), envFileContent);
|
|
95
168
|
try {
|
|
96
|
-
|
|
169
|
+
const deployType = CHANNEL ? `hosting:channel:deploy ${CHANNEL.name} --expires ${CHANNEL.expiration}` : 'deploy';
|
|
170
|
+
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
171
|
} catch (err) {
|
|
98
172
|
console.error(err);
|
|
99
173
|
}
|
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.1",
|
|
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",
|
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,24 @@ 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
|
+
|
|
14
33
|
let exited = false
|
|
15
34
|
|
|
16
35
|
const SECRETS_DIR = 'secrets'
|
|
@@ -18,10 +37,12 @@ const EXIT_EVENTS = [ 'SIGINT', 'exit', 'uncaughException', 'unhandledRejection'
|
|
|
18
37
|
|
|
19
38
|
const [
|
|
20
39
|
firebaserc,
|
|
21
|
-
firebaseJson
|
|
40
|
+
firebaseJson,
|
|
41
|
+
git
|
|
22
42
|
] = await Promise.all( [
|
|
23
43
|
fs.exists( path.join( process.cwd(), '.firebaserc' ) ),
|
|
24
|
-
fs.exists( path.join( process.cwd(), 'firebase.json' ) )
|
|
44
|
+
fs.exists( path.join( process.cwd(), 'firebase.json' ) ),
|
|
45
|
+
fs.exists( path.join( process.cwd(), '.git/HEAD' ) )
|
|
25
46
|
] )
|
|
26
47
|
|
|
27
48
|
if ( !firebaserc ) {
|
|
@@ -38,17 +59,29 @@ if ( !firebaserc || !firebaseJson ) {
|
|
|
38
59
|
|
|
39
60
|
const firebasercContent = JSON.parse( await fs.readFile( path.join( process.cwd(), '.firebaserc' ), { encoding : 'utf-8' } ) )
|
|
40
61
|
|
|
62
|
+
// If in a git repo, fetch the name of the git branch to use as a default
|
|
63
|
+
// name in case a deployment channel is needed
|
|
64
|
+
let gitBranch
|
|
65
|
+
if ( git ) {
|
|
66
|
+
const gitContent = ( await fs.readFile( path.join( process.cwd(), '.git/HEAD' ), { encoding : 'utf-8' } ) )?.split( '/' )
|
|
67
|
+
gitBranch = gitContent[gitContent?.length - 1]?.trimEnd( '\n' )
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let maxPadding = 0
|
|
71
|
+
|
|
41
72
|
const targets = Object
|
|
42
73
|
.entries( firebasercContent.targets )
|
|
43
|
-
.reduce( ( prev, [ projectId, config ] ) => {
|
|
74
|
+
.reduce( ( prev, [ projectId, config, production ] ) => {
|
|
44
75
|
Object
|
|
45
76
|
.entries( config.hosting )
|
|
46
|
-
.forEach( ( [ siteId, aliases ] ) => {
|
|
77
|
+
.forEach( ( [ siteId, aliases, production ] ) => {
|
|
47
78
|
aliases.forEach( ( alias ) => {
|
|
79
|
+
maxPadding = Math.max( siteId.length, maxPadding )
|
|
48
80
|
prev[alias] = {
|
|
49
81
|
projectId,
|
|
50
82
|
siteId,
|
|
51
|
-
alias
|
|
83
|
+
alias,
|
|
84
|
+
production : config.production
|
|
52
85
|
}
|
|
53
86
|
} )
|
|
54
87
|
} )
|
|
@@ -57,14 +90,52 @@ const targets = Object
|
|
|
57
90
|
}, {} )
|
|
58
91
|
|
|
59
92
|
if ( !TARGET ) {
|
|
60
|
-
const { targetEnv } = await prompt( {
|
|
61
|
-
type : '
|
|
93
|
+
const { targetEnv } = await prompt( [ {
|
|
94
|
+
type : 'select',
|
|
62
95
|
name : 'targetEnv',
|
|
63
96
|
message : 'To which environment would you like to deploy?',
|
|
64
|
-
choices : Object.
|
|
65
|
-
|
|
97
|
+
choices : Object.values( targets ).map( ( t ) => {
|
|
98
|
+
const productionLabel = t.production ? colors.bold.red( '--PRODUCTION--' ) : ''
|
|
99
|
+
return { message : `${colors.bold.cyan( 'Site: ' )}${t.siteId.padEnd( maxPadding )} ${colors.bold.green( 'Project: ' )}${t.projectId} ${productionLabel}`, value : t.siteId }
|
|
100
|
+
} )
|
|
101
|
+
} ] )
|
|
66
102
|
|
|
67
103
|
TARGET = targets[targetEnv]
|
|
104
|
+
|
|
105
|
+
if ( TARGET.production ) {
|
|
106
|
+
const { confirmProductionDeploy } = await prompt( [ {
|
|
107
|
+
type : 'confirm',
|
|
108
|
+
name : 'confirmProductionDeploy',
|
|
109
|
+
message : `${colors.bold.red( 'WARNING: ' )} This is a ${colors.bold.yellow( 'PRODUCTION' )} deployment target. Are you sure you want to proceed?`
|
|
110
|
+
} ] )
|
|
111
|
+
if ( !confirmProductionDeploy ) {
|
|
112
|
+
console.log( 'Cancelling deployment...' )
|
|
113
|
+
process.exit()
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const { useChannel } = await prompt( [ {
|
|
118
|
+
type : 'confirm',
|
|
119
|
+
name : 'useChannel',
|
|
120
|
+
message : 'Do you want to deploy to a temporary preview channel?'
|
|
121
|
+
} ] )
|
|
122
|
+
|
|
123
|
+
if ( useChannel ) {
|
|
124
|
+
const { channelName, channelExpiration } = await prompt( [ {
|
|
125
|
+
type : 'input',
|
|
126
|
+
name : 'channelName',
|
|
127
|
+
message : 'To which channel would you like to deploy?',
|
|
128
|
+
initial : gitBranch ?? 'temp-deploy'
|
|
129
|
+
}, {
|
|
130
|
+
type : 'input',
|
|
131
|
+
name : 'channelExpiration',
|
|
132
|
+
message : 'When should the channel expire?',
|
|
133
|
+
initial : '7d'
|
|
134
|
+
} ] )
|
|
135
|
+
|
|
136
|
+
CHANNEL = { name : channelName, expiration : channelExpiration }
|
|
137
|
+
}
|
|
138
|
+
|
|
68
139
|
} else {
|
|
69
140
|
TARGET = targets[TARGET]
|
|
70
141
|
}
|
|
@@ -112,7 +183,8 @@ EXIT_EVENTS
|
|
|
112
183
|
await fs.writeFile( path.join( process.cwd(), '.env.temp' ), envFileContent )
|
|
113
184
|
|
|
114
185
|
try {
|
|
115
|
-
|
|
186
|
+
const deployType = CHANNEL ? `hosting:channel:deploy ${CHANNEL.name} --expires ${CHANNEL.expiration}` : 'deploy'
|
|
187
|
+
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
188
|
} catch ( err ) {
|
|
117
189
|
console.error( err )
|
|
118
190
|
}
|