@cloudcommerce/cli 0.0.48 → 0.0.51

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.
@@ -1,5 +1,5 @@
1
- @cloudcommerce/cli:build: cache hit, replaying output 1d924682dc793266
1
+ @cloudcommerce/cli:build: cache hit, replaying output 2cc60bd241fc5476
2
2
  @cloudcommerce/cli:build: 
3
- @cloudcommerce/cli:build: > @cloudcommerce/cli@0.0.47 build /home/leo/code/ecomplus/cloud-commerce/packages/cli
3
+ @cloudcommerce/cli:build: > @cloudcommerce/cli@0.0.50 build /home/leo/code/ecomplus/cloud-commerce/packages/cli
4
4
  @cloudcommerce/cli:build: > sh ../../scripts/build-lib.sh
5
5
  @cloudcommerce/cli:build: 
@@ -9,6 +9,11 @@
9
9
  "source": "functions/core",
10
10
  "codebase": "core"
11
11
  },
12
+ {
13
+ "predeploy": "npm run build -- --codebase events --dir \"$RESOURCE_DIR\"",
14
+ "source": "functions/events",
15
+ "codebase": "events"
16
+ },
12
17
  {
13
18
  "predeploy": "npm run build -- --codebase modules --dir \"$RESOURCE_DIR\"",
14
19
  "source": "functions/modules",
@@ -0,0 +1,79 @@
1
+ import path from 'path';
2
+ import { $, echo, fs } from 'zx';
3
+
4
+ const serviceAccountId = 'cloud-commerce-gh-actions';
5
+ const serviceAccountEmail = (projectId) => {
6
+ return `${serviceAccountId}@${projectId}.iam.gserviceaccount.com`;
7
+ };
8
+ const checkServiceAccountExists = async (projectId) => {
9
+ try {
10
+ return $`gcloud iam service-accounts describe ${serviceAccountEmail(projectId)}`;
11
+ } catch (e) {
12
+ return null;
13
+ }
14
+ };
15
+ const siginGcloudAndSetIAM = async (projectId, pwd) => {
16
+ await $`gcloud auth login`;
17
+ await $`gcloud config set project ${projectId} `;
18
+ const roles = [
19
+ 'roles/cloudconfig.admin',
20
+ 'roles/appengine.appAdmin',
21
+ 'roles/appengine.appCreator',
22
+ 'roles/artifactregistry.admin',
23
+ 'roles/cloudfunctions.admin',
24
+ 'roles/cloudscheduler.admin',
25
+ 'roles/iam.serviceAccountUser',
26
+ 'roles/run.viewer',
27
+ 'roles/serviceusage.apiKeysViewer',
28
+ ];
29
+ const serviceAccount = await checkServiceAccountExists(projectId);
30
+ if (!serviceAccount) {
31
+ await $`gcloud iam service-accounts create ${serviceAccountId} \
32
+ --description="A service account with permission to deploy Cloud Commerce from the GitHub repository to Firebase" \
33
+ --display-name="Cloud Commerce GH Actions"`;
34
+ }
35
+ const pathPolicyIAM = path.join(pwd, 'policyIAM.json');
36
+ await $`gcloud projects get-iam-policy ${projectId} --format json > ${pathPolicyIAM}`;
37
+ const policyIAM = fs.readJSONSync(pathPolicyIAM);
38
+ const { bindings } = policyIAM;
39
+ let updatePolicy = false;
40
+ roles.forEach((role) => {
41
+ const roleFound = bindings.find((binding) => binding.role === role);
42
+ const memberServiceAccount = `serviceAccount:${serviceAccountEmail(projectId)}`;
43
+ if (!roleFound) {
44
+ const newBinding = {
45
+ members: [
46
+ memberServiceAccount,
47
+ ],
48
+ role,
49
+ };
50
+ bindings.push(newBinding);
51
+ updatePolicy = true;
52
+ } else {
53
+ const serviceAccountHavePermission = roleFound.members.find((account) => account === memberServiceAccount);
54
+ if (!serviceAccountHavePermission) {
55
+ roleFound.members.push(memberServiceAccount);
56
+ updatePolicy = true;
57
+ }
58
+ }
59
+ });
60
+ if (updatePolicy) {
61
+ fs.writeJSONSync(pathPolicyIAM, policyIAM);
62
+ return $`gcloud projects set-iam-policy ${projectId} ${pathPolicyIAM}`;
63
+ }
64
+ return echo``;
65
+ };
66
+ const createKeyServiceAccount = async (projectId, pwd) => {
67
+ try {
68
+ const pathFileKey = path.join(pwd, 'serviceAccountKey.json');
69
+ await $`gcloud iam service-accounts keys create ${pathFileKey} \
70
+ --iam-account=${serviceAccountEmail(projectId)}`;
71
+ return JSON.stringify(fs.readJSONSync(pathFileKey));
72
+ } catch (e) {
73
+ return null;
74
+ }
75
+ };
76
+
77
+ export default siginGcloudAndSetIAM;
78
+
79
+ export { siginGcloudAndSetIAM, createKeyServiceAccount };
@@ -26,15 +26,15 @@ export default async (storeId, accessToken) => {
26
26
  username: `cloudcomm${Date.now()}`,
27
27
  permissions: {
28
28
  applications: ['all'],
29
- brands: ['GET'],
30
- carts: ['all'],
31
- categories: ['GET'],
32
- collections: ['GET'],
29
+ brands: ['all'],
30
+ categories: ['all'],
31
+ collections: ['all'],
32
+ grids: ['all'],
33
+ products: ['all'],
33
34
  customers: ['all'],
34
- grids: ['GET'],
35
+ carts: ['all'],
35
36
  orders: ['GET', 'POST', 'PATCH'],
36
- products: ['GET', 'PATCH'],
37
- stores: ['GET'],
37
+ stores: ['GET', 'PATCH'],
38
38
  },
39
39
  }, apiConfig);
40
40
  authenticationId = _id;
package/lib/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  } from 'zx';
6
6
  import login from './login.js';
7
7
  import build from './build.js';
8
+ import { siginGcloudAndSetIAM, createKeyServiceAccount } from './config-gcloud.js';
8
9
 
9
10
  const { FIREBASE_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS } = process.env;
10
11
  const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
@@ -43,6 +44,9 @@ export default async () => {
43
44
  return opts;
44
45
  }, '');
45
46
  const $firebase = (cmd) => {
47
+ if (cmd === 'deploy') {
48
+ return $`firebase --project=${projectId} ${cmd}${options} --force`;
49
+ }
46
50
  return $`firebase --project=${projectId} ${cmd}${options}`;
47
51
  };
48
52
  if (argv._.includes('serve')) {
@@ -94,6 +98,13 @@ ECOM_STORE_ID=${storeId}
94
98
  //
95
99
  }
96
100
  }
101
+ let serviceAccountJSON = null;
102
+ try {
103
+ await siginGcloudAndSetIAM(projectId, pwd);
104
+ serviceAccountJSON = await createKeyServiceAccount(projectId, pwd);
105
+ } catch (e) {
106
+ //
107
+ }
97
108
  return echo`
98
109
  ****
99
110
 
@@ -103,7 +114,7 @@ Finish by saving the following secrets to your GitHub repository:
103
114
 
104
115
  ${chalk.bold('ECOM_API_KEY')} = ${chalk.bgMagenta(apiKey)}
105
116
 
106
- ${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = {YOUR_SERVICE_ACCOUNT_JSON}
117
+ ${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = ${chalk.bgMagenta(serviceAccountJSON || '{YOUR_SERVICE_ACCOUNT_JSON}')}
107
118
 
108
119
  -- More info at https://github.com/ecomplus/store#getting-started
109
120
  `;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudcommerce/cli",
3
3
  "type": "module",
4
- "version": "0.0.48",
4
+ "version": "0.0.51",
5
5
  "description": "E-Com Plus Cloud Commerce CLI tools",
6
6
  "bin": {
7
7
  "cloudcommerce": "./bin/run.mjs"
@@ -23,9 +23,9 @@
23
23
  },
24
24
  "homepage": "https://github.com/ecomplus/cloud-commerce/tree/main/packages/cli#readme",
25
25
  "dependencies": {
26
- "@cloudcommerce/api": "0.0.48",
26
+ "@cloudcommerce/api": "0.0.51",
27
27
  "md5": "^2.3.0",
28
- "zx": "^7.0.7"
28
+ "zx": "^7.0.8"
29
29
  },
30
30
  "scripts": {
31
31
  "build": "sh ../../scripts/build-lib.sh"
@@ -0,0 +1,93 @@
1
+ import path from 'path';
2
+ import { $, echo, fs } from 'zx';
3
+
4
+ const serviceAccountId = 'cloud-commerce-gh-actions';
5
+ const serviceAccountEmail = (projectId: string) => {
6
+ return `${serviceAccountId}@${projectId}.iam.gserviceaccount.com`;
7
+ };
8
+
9
+ const checkServiceAccountExists = async (projectId: string) => {
10
+ try {
11
+ return $`gcloud iam service-accounts describe ${serviceAccountEmail(projectId)}`;
12
+ } catch (e) {
13
+ return null;
14
+ }
15
+ };
16
+
17
+ const siginGcloudAndSetIAM = async (
18
+ projectId: string,
19
+ pwd: string,
20
+ ) => {
21
+ await $`gcloud auth login`;
22
+ await $`gcloud config set project ${projectId} `;
23
+ const roles = [
24
+ 'roles/cloudconfig.admin',
25
+ 'roles/appengine.appAdmin',
26
+ 'roles/appengine.appCreator',
27
+ 'roles/artifactregistry.admin',
28
+ 'roles/cloudfunctions.admin',
29
+ 'roles/cloudscheduler.admin',
30
+ 'roles/iam.serviceAccountUser',
31
+ 'roles/run.viewer',
32
+ 'roles/serviceusage.apiKeysViewer',
33
+ ];
34
+ const serviceAccount = await checkServiceAccountExists(projectId);
35
+ if (!serviceAccount) {
36
+ await $`gcloud iam service-accounts create ${serviceAccountId} \
37
+ --description="A service account with permission to deploy Cloud Commerce from the GitHub repository to Firebase" \
38
+ --display-name="Cloud Commerce GH Actions"`;
39
+ }
40
+ const pathPolicyIAM = path.join(pwd, 'policyIAM.json');
41
+ await $`gcloud projects get-iam-policy ${projectId} --format json > ${pathPolicyIAM}`;
42
+ const policyIAM = fs.readJSONSync(pathPolicyIAM);
43
+ const { bindings } = policyIAM;
44
+ let updatePolicy = false;
45
+
46
+ roles.forEach((role) => {
47
+ const roleFound = bindings.find(
48
+ (binding: { [key: string]: string | string[] }) => binding.role === role,
49
+ );
50
+ const memberServiceAccount = `serviceAccount:${serviceAccountEmail(projectId)}`;
51
+ if (!roleFound) {
52
+ const newBinding = {
53
+ members: [
54
+ memberServiceAccount,
55
+ ],
56
+ role,
57
+ };
58
+ bindings.push(newBinding);
59
+ updatePolicy = true;
60
+ } else {
61
+ const serviceAccountHavePermission = roleFound.members.find(
62
+ (account: string) => account === memberServiceAccount,
63
+ );
64
+ if (!serviceAccountHavePermission) {
65
+ roleFound.members.push(memberServiceAccount);
66
+ updatePolicy = true;
67
+ }
68
+ }
69
+ });
70
+ if (updatePolicy) {
71
+ fs.writeJSONSync(pathPolicyIAM, policyIAM);
72
+ return $`gcloud projects set-iam-policy ${projectId} ${pathPolicyIAM}`;
73
+ }
74
+ return echo``;
75
+ };
76
+
77
+ const createKeyServiceAccount = async (projectId: string, pwd: string) => {
78
+ try {
79
+ const pathFileKey = path.join(pwd, 'serviceAccountKey.json');
80
+ await $`gcloud iam service-accounts keys create ${pathFileKey} \
81
+ --iam-account=${serviceAccountEmail(projectId)}`;
82
+ return JSON.stringify(fs.readJSONSync(pathFileKey));
83
+ } catch (e) {
84
+ return null;
85
+ }
86
+ };
87
+
88
+ export default siginGcloudAndSetIAM;
89
+
90
+ export {
91
+ siginGcloudAndSetIAM,
92
+ createKeyServiceAccount,
93
+ };
@@ -27,15 +27,15 @@ export default async (storeId: number, accessToken: string) => {
27
27
  username: `cloudcomm${Date.now()}`,
28
28
  permissions: {
29
29
  applications: ['all'],
30
- brands: ['GET'],
31
- carts: ['all'],
32
- categories: ['GET'],
33
- collections: ['GET'],
30
+ brands: ['all'],
31
+ categories: ['all'],
32
+ collections: ['all'],
33
+ grids: ['all'],
34
+ products: ['all'],
34
35
  customers: ['all'],
35
- grids: ['GET'],
36
+ carts: ['all'],
36
37
  orders: ['GET', 'POST', 'PATCH'],
37
- products: ['GET', 'PATCH'],
38
- stores: ['GET'],
38
+ stores: ['GET', 'PATCH'],
39
39
  },
40
40
  }, apiConfig);
41
41
  authenticationId = _id;
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  } from 'zx';
10
10
  import login from './login';
11
11
  import build from './build';
12
+ import { siginGcloudAndSetIAM, createKeyServiceAccount } from './config-gcloud';
12
13
 
13
14
  const {
14
15
  FIREBASE_PROJECT_ID,
@@ -56,6 +57,9 @@ export default async () => {
56
57
  return opts;
57
58
  }, '');
58
59
  const $firebase = (cmd: string) => {
60
+ if (cmd === 'deploy') {
61
+ return $`firebase --project=${projectId} ${cmd}${options} --force`;
62
+ }
59
63
  return $`firebase --project=${projectId} ${cmd}${options}`;
60
64
  };
61
65
 
@@ -116,6 +120,14 @@ ECOM_STORE_ID=${storeId}
116
120
  //
117
121
  }
118
122
  }
123
+ let serviceAccountJSON : string | null = null;
124
+ try {
125
+ await siginGcloudAndSetIAM(projectId as string, pwd);
126
+ serviceAccountJSON = await createKeyServiceAccount(projectId as string, pwd);
127
+ } catch (e) {
128
+ //
129
+ }
130
+
119
131
  return echo`
120
132
  ****
121
133
 
@@ -125,11 +137,10 @@ Finish by saving the following secrets to your GitHub repository:
125
137
 
126
138
  ${chalk.bold('ECOM_API_KEY')} = ${chalk.bgMagenta(apiKey)}
127
139
 
128
- ${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = {YOUR_SERVICE_ACCOUNT_JSON}
140
+ ${chalk.bold('FIREBASE_SERVICE_ACCOUNT')} = ${chalk.bgMagenta(serviceAccountJSON || '{YOUR_SERVICE_ACCOUNT_JSON}')}
129
141
 
130
142
  -- More info at https://github.com/ecomplus/store#getting-started
131
143
  `;
132
144
  }
133
-
134
145
  return $`echo 'Hello from @cloudcommerce/cli'`;
135
146
  };