@cloudcommerce/cli 0.0.56 → 0.0.59
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/.turbo/turbo-build.log +5 -5
- package/config/firebase.json +6 -3
- package/lib/index.js +23 -4
- package/lib/{config-gcloud.js → setup-gcloud.js} +2 -2
- package/lib/setup-gh.js +59 -0
- package/package.json +3 -2
- package/src/index.ts +30 -3
- package/src/{config-gcloud.ts → setup-gcloud.ts} +2 -2
- package/src/setup-gh.ts +83 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
[
|
|
2
|
-
[
|
|
3
|
-
[
|
|
4
|
-
[
|
|
5
|
-
[
|
|
1
|
+
[33m@cloudcommerce/cli:build[0m: cache hit, replaying output [2m5d6d6833e3e71f68[0m
|
|
2
|
+
[33m@cloudcommerce/cli:build: [0m
|
|
3
|
+
[33m@cloudcommerce/cli:build: [0m> @cloudcommerce/cli@0.0.58 build /home/leo/code/ecomplus/cloud-commerce/packages/cli
|
|
4
|
+
[33m@cloudcommerce/cli:build: [0m> sh ../../scripts/build-lib.sh
|
|
5
|
+
[33m@cloudcommerce/cli:build: [0m
|
package/config/firebase.json
CHANGED
|
@@ -40,15 +40,18 @@
|
|
|
40
40
|
"rewrites": [
|
|
41
41
|
{
|
|
42
42
|
"source": "/api/modules/**",
|
|
43
|
-
"function": "modules"
|
|
43
|
+
"function": "modules",
|
|
44
|
+
"region": "southamerica-east1"
|
|
44
45
|
},
|
|
45
46
|
{
|
|
46
47
|
"source": "/api/passport/**",
|
|
47
|
-
"function": "passport"
|
|
48
|
+
"function": "passport",
|
|
49
|
+
"region": "southamerica-east1"
|
|
48
50
|
},
|
|
49
51
|
{
|
|
50
52
|
"source": "**/!(*(*.)js|*(*.)css|*(*.)ico|*(*.)png|*(*.)gif|*(*.)jpg|*(*.)jpeg|*(*.)webp|*(*.)avif|*(*.)svg|*(*.)woff|*(*.)woff2|*(*.)otf|*(*.)ttf|*(*.)eot)",
|
|
51
|
-
"function": "ssr"
|
|
53
|
+
"function": "ssr",
|
|
54
|
+
"region": "southamerica-east1"
|
|
52
55
|
}
|
|
53
56
|
],
|
|
54
57
|
"cleanUrls": true
|
package/lib/index.js
CHANGED
|
@@ -5,9 +5,10 @@ import {
|
|
|
5
5
|
} from 'zx';
|
|
6
6
|
import login from './login.js';
|
|
7
7
|
import build from './build.js';
|
|
8
|
-
import { siginGcloudAndSetIAM,
|
|
8
|
+
import { siginGcloudAndSetIAM, createServiceAccountKey } from './setup-gcloud.js';
|
|
9
|
+
import createGhSecrets from './setup-gh.js';
|
|
9
10
|
|
|
10
|
-
const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS } = process.env;
|
|
11
|
+
const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS, GITHUB_TOKEN } = process.env;
|
|
11
12
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
12
13
|
const pwd = process.cwd();
|
|
13
14
|
let projectId = FIREBASE_PROJECT_ID;
|
|
@@ -29,7 +30,7 @@ if (projectId) {
|
|
|
29
30
|
const firebaserc = fs.readJSONSync(path.join(pwd, '.firebaserc'));
|
|
30
31
|
projectId = firebaserc.projects.default;
|
|
31
32
|
} catch (e) {
|
|
32
|
-
projectId = 'ecom2-
|
|
33
|
+
projectId = 'ecom2-002';
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -102,11 +103,29 @@ ECOM_STORE_ID=${storeId}
|
|
|
102
103
|
if (argv.gcloud !== false) {
|
|
103
104
|
try {
|
|
104
105
|
await siginGcloudAndSetIAM(projectId, pwd);
|
|
105
|
-
serviceAccountJSON = await
|
|
106
|
+
serviceAccountJSON = await createServiceAccountKey(projectId, pwd);
|
|
106
107
|
} catch (e) {
|
|
107
108
|
//
|
|
108
109
|
}
|
|
109
110
|
}
|
|
111
|
+
let hasCreatedAllSecrets = false;
|
|
112
|
+
if (GITHUB_TOKEN && argv.github !== false) {
|
|
113
|
+
try {
|
|
114
|
+
hasCreatedAllSecrets = await createGhSecrets(apiKey, authenticationId, serviceAccountJSON, GITHUB_TOKEN);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
//
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (hasCreatedAllSecrets) {
|
|
120
|
+
return echo`
|
|
121
|
+
****
|
|
122
|
+
|
|
123
|
+
CloudCommerce setup completed successfully.
|
|
124
|
+
Your store repository on GitHub is ready, the first deploy will automatically start with GH Actions.
|
|
125
|
+
|
|
126
|
+
-- More info at https://github.com/ecomplus/store#getting-started
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
110
129
|
return echo`
|
|
111
130
|
****
|
|
112
131
|
|
|
@@ -78,7 +78,7 @@ const siginGcloudAndSetIAM = async (projectId, pwd) => {
|
|
|
78
78
|
}
|
|
79
79
|
return null;
|
|
80
80
|
};
|
|
81
|
-
const
|
|
81
|
+
const createServiceAccountKey = async (projectId, pwd) => {
|
|
82
82
|
try {
|
|
83
83
|
const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
|
|
84
84
|
await $`gcloud iam service-accounts keys create ${pathFileKey} \
|
|
@@ -91,4 +91,4 @@ const createKeyServiceAccount = async (projectId, pwd) => {
|
|
|
91
91
|
|
|
92
92
|
export default siginGcloudAndSetIAM;
|
|
93
93
|
|
|
94
|
-
export { siginGcloudAndSetIAM,
|
|
94
|
+
export { siginGcloudAndSetIAM, createServiceAccountKey };
|
package/lib/setup-gh.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { fetch, $ } from 'zx';
|
|
2
|
+
import libsodium from 'libsodium-wrappers';
|
|
3
|
+
|
|
4
|
+
const getRemoteRepo = async () => {
|
|
5
|
+
try {
|
|
6
|
+
return (await $`git config --get remote.origin.url`).stdout
|
|
7
|
+
.replace(/.*github.com[/:]/, '')
|
|
8
|
+
.replace('.git', '')
|
|
9
|
+
.replace('\n', '');
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const createGhSecrets = async (ecomApiKey, ecomAuthentication, firebaseServiceAccount, ghToken, ghRepo) => {
|
|
15
|
+
const remoteRepo = ghRepo || await getRemoteRepo();
|
|
16
|
+
if (!remoteRepo) {
|
|
17
|
+
throw new Error("Can't define remote Git repository");
|
|
18
|
+
}
|
|
19
|
+
const baseUrl = `https://api.github.com/repos/${remoteRepo}/actions/secrets`;
|
|
20
|
+
const fetchGhSecrets = async (resource, body, method = 'GET') => {
|
|
21
|
+
const url = `${baseUrl}${resource}`;
|
|
22
|
+
const headers = {
|
|
23
|
+
Accept: 'application/vnd.github+json',
|
|
24
|
+
Authorization: `token ${ghToken}`,
|
|
25
|
+
};
|
|
26
|
+
return fetch(url, {
|
|
27
|
+
method,
|
|
28
|
+
headers,
|
|
29
|
+
body,
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
// https:// docs.github.com/pt/rest/actions/secrets#get-a-repository-public-key
|
|
33
|
+
const ghPublicKey = await (await fetchGhSecrets('/public-key')).json();
|
|
34
|
+
const ghKeyBuffer = Buffer.from(ghPublicKey.key, 'base64');
|
|
35
|
+
await libsodium.ready;
|
|
36
|
+
const createGhSecret = async (secretName, secretValue) => {
|
|
37
|
+
// https://docs.github.com/pt/rest/actions/secrets#example-encrypting-a-secret-using-nodejs
|
|
38
|
+
// Encryption example: https://github.com/github/tweetsodium
|
|
39
|
+
const encryptedBytes = libsodium.crypto_box_seal(Buffer.from(secretValue), ghKeyBuffer);
|
|
40
|
+
const body = {
|
|
41
|
+
encrypted_value: Buffer.from(encryptedBytes).toString('base64'),
|
|
42
|
+
key_id: ghPublicKey.key_id,
|
|
43
|
+
};
|
|
44
|
+
return fetchGhSecrets(`/${secretName}`, JSON.stringify(body), 'PUT');
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
await createGhSecret('ECOM_API_KEY', ecomApiKey);
|
|
48
|
+
await createGhSecret('ECOM_AUTHENTICATION_ID', ecomAuthentication);
|
|
49
|
+
if (firebaseServiceAccount) {
|
|
50
|
+
await createGhSecret('FIREBASE_SERVICE_ACCOUNT', firebaseServiceAccount);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
} catch (e) {
|
|
54
|
+
//
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default createGhSecrets;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudcommerce/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.59",
|
|
5
5
|
"description": "E-Com Plus Cloud Commerce CLI tools",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cloudcommerce": "./bin/run.mjs"
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://github.com/ecomplus/cloud-commerce/tree/main/packages/cli#readme",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@cloudcommerce/api": "0.0.
|
|
26
|
+
"@cloudcommerce/api": "0.0.59",
|
|
27
|
+
"libsodium-wrappers": "^0.7.10",
|
|
27
28
|
"md5": "^2.3.0",
|
|
28
29
|
"zx": "^7.0.8"
|
|
29
30
|
},
|
package/src/index.ts
CHANGED
|
@@ -9,11 +9,13 @@ import {
|
|
|
9
9
|
} from 'zx';
|
|
10
10
|
import login from './login';
|
|
11
11
|
import build from './build';
|
|
12
|
-
import { siginGcloudAndSetIAM,
|
|
12
|
+
import { siginGcloudAndSetIAM, createServiceAccountKey } from './setup-gcloud';
|
|
13
|
+
import createGhSecrets from './setup-gh';
|
|
13
14
|
|
|
14
15
|
const {
|
|
15
16
|
FIREBASE_PROJECT_ID,
|
|
16
17
|
GOOGLE_APPLICATION_CREDENTIALS,
|
|
18
|
+
GITHUB_TOKEN,
|
|
17
19
|
} = process.env;
|
|
18
20
|
|
|
19
21
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
@@ -41,7 +43,7 @@ if (projectId) {
|
|
|
41
43
|
const firebaserc = fs.readJSONSync(path.join(pwd, '.firebaserc'));
|
|
42
44
|
projectId = firebaserc.projects.default;
|
|
43
45
|
} catch (e) {
|
|
44
|
-
projectId = 'ecom2-
|
|
46
|
+
projectId = 'ecom2-002';
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
}
|
|
@@ -103,6 +105,7 @@ ECOM_API_KEY=${apiKey}
|
|
|
103
105
|
ECOM_STORE_ID=${storeId}
|
|
104
106
|
`,
|
|
105
107
|
);
|
|
108
|
+
|
|
106
109
|
if (argv.deploy !== false) {
|
|
107
110
|
await $firebase('deploy');
|
|
108
111
|
}
|
|
@@ -111,6 +114,7 @@ ECOM_STORE_ID=${storeId}
|
|
|
111
114
|
path.join(pwd, 'functions', 'config.json'),
|
|
112
115
|
JSON.stringify({ storeId }, null, 2),
|
|
113
116
|
);
|
|
117
|
+
|
|
114
118
|
await build();
|
|
115
119
|
try {
|
|
116
120
|
await $`git add .firebaserc functions/config.json`;
|
|
@@ -124,12 +128,35 @@ ECOM_STORE_ID=${storeId}
|
|
|
124
128
|
if (argv.gcloud !== false) {
|
|
125
129
|
try {
|
|
126
130
|
await siginGcloudAndSetIAM(projectId as string, pwd);
|
|
127
|
-
serviceAccountJSON = await
|
|
131
|
+
serviceAccountJSON = await createServiceAccountKey(projectId as string, pwd);
|
|
132
|
+
} catch (e) {
|
|
133
|
+
//
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
let hasCreatedAllSecrets = false;
|
|
137
|
+
if (GITHUB_TOKEN && argv.github !== false) {
|
|
138
|
+
try {
|
|
139
|
+
hasCreatedAllSecrets = await createGhSecrets(
|
|
140
|
+
apiKey,
|
|
141
|
+
authenticationId,
|
|
142
|
+
serviceAccountJSON,
|
|
143
|
+
GITHUB_TOKEN,
|
|
144
|
+
);
|
|
128
145
|
} catch (e) {
|
|
129
146
|
//
|
|
130
147
|
}
|
|
131
148
|
}
|
|
132
149
|
|
|
150
|
+
if (hasCreatedAllSecrets) {
|
|
151
|
+
return echo`
|
|
152
|
+
****
|
|
153
|
+
|
|
154
|
+
CloudCommerce setup completed successfully.
|
|
155
|
+
Your store repository on GitHub is ready, the first deploy will automatically start with GH Actions.
|
|
156
|
+
|
|
157
|
+
-- More info at https://github.com/ecomplus/store#getting-started
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
133
160
|
return echo`
|
|
134
161
|
****
|
|
135
162
|
|
|
@@ -84,7 +84,7 @@ const siginGcloudAndSetIAM = async (projectId: string, pwd: string) => {
|
|
|
84
84
|
return null;
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
const
|
|
87
|
+
const createServiceAccountKey = async (projectId: string, pwd: string) => {
|
|
88
88
|
try {
|
|
89
89
|
const pathFileKey = path.join(pwd, '.cloudcommerce', 'serviceAccountKey.json');
|
|
90
90
|
await $`gcloud iam service-accounts keys create ${pathFileKey} \
|
|
@@ -99,5 +99,5 @@ export default siginGcloudAndSetIAM;
|
|
|
99
99
|
|
|
100
100
|
export {
|
|
101
101
|
siginGcloudAndSetIAM,
|
|
102
|
-
|
|
102
|
+
createServiceAccountKey,
|
|
103
103
|
};
|
package/src/setup-gh.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { fetch, $ } from 'zx';
|
|
2
|
+
import libsodium from 'libsodium-wrappers';
|
|
3
|
+
|
|
4
|
+
const getRemoteRepo = async () => {
|
|
5
|
+
try {
|
|
6
|
+
return (await $`git config --get remote.origin.url`).stdout
|
|
7
|
+
.replace(/.*github.com[/:]/, '')
|
|
8
|
+
.replace('.git', '')
|
|
9
|
+
.replace('\n', '');
|
|
10
|
+
} catch (e) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const createGhSecrets = async (
|
|
16
|
+
ecomApiKey: string,
|
|
17
|
+
ecomAuthentication: string,
|
|
18
|
+
firebaseServiceAccount: string | null,
|
|
19
|
+
ghToken: string,
|
|
20
|
+
ghRepo?: string,
|
|
21
|
+
) => {
|
|
22
|
+
const remoteRepo = ghRepo || await getRemoteRepo();
|
|
23
|
+
if (!remoteRepo) {
|
|
24
|
+
throw new Error("Can't define remote Git repository");
|
|
25
|
+
}
|
|
26
|
+
const baseUrl = `https://api.github.com/repos/${remoteRepo}/actions/secrets`;
|
|
27
|
+
|
|
28
|
+
const fetchGhSecrets = async (
|
|
29
|
+
resource: string,
|
|
30
|
+
body?: string,
|
|
31
|
+
method: string = 'GET',
|
|
32
|
+
) => {
|
|
33
|
+
const url = `${baseUrl}${resource}`;
|
|
34
|
+
const headers = {
|
|
35
|
+
Accept: 'application/vnd.github+json',
|
|
36
|
+
Authorization: `token ${ghToken}`,
|
|
37
|
+
};
|
|
38
|
+
return fetch(url, {
|
|
39
|
+
method,
|
|
40
|
+
headers,
|
|
41
|
+
body,
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// https:// docs.github.com/pt/rest/actions/secrets#get-a-repository-public-key
|
|
46
|
+
const ghPublicKey = await (await fetchGhSecrets('/public-key')).json() as {
|
|
47
|
+
key_id: string,
|
|
48
|
+
key: string,
|
|
49
|
+
};
|
|
50
|
+
const ghKeyBuffer = Buffer.from(ghPublicKey.key, 'base64');
|
|
51
|
+
await libsodium.ready;
|
|
52
|
+
|
|
53
|
+
const createGhSecret = async (
|
|
54
|
+
secretName: string,
|
|
55
|
+
secretValue: string,
|
|
56
|
+
) => {
|
|
57
|
+
// https://docs.github.com/pt/rest/actions/secrets#example-encrypting-a-secret-using-nodejs
|
|
58
|
+
// Encryption example: https://github.com/github/tweetsodium
|
|
59
|
+
const encryptedBytes = libsodium.crypto_box_seal(
|
|
60
|
+
Buffer.from(secretValue),
|
|
61
|
+
ghKeyBuffer,
|
|
62
|
+
);
|
|
63
|
+
const body = {
|
|
64
|
+
encrypted_value: Buffer.from(encryptedBytes).toString('base64'),
|
|
65
|
+
key_id: ghPublicKey.key_id,
|
|
66
|
+
};
|
|
67
|
+
return fetchGhSecrets(`/${secretName}`, JSON.stringify(body), 'PUT');
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
await createGhSecret('ECOM_API_KEY', ecomApiKey);
|
|
72
|
+
await createGhSecret('ECOM_AUTHENTICATION_ID', ecomAuthentication);
|
|
73
|
+
if (firebaseServiceAccount) {
|
|
74
|
+
await createGhSecret('FIREBASE_SERVICE_ACCOUNT', firebaseServiceAccount);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
} catch (e) {
|
|
78
|
+
//
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export default createGhSecrets;
|