nitor 1.1.0 → 1.2.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/CHANGELOG.md +7 -1
- package/README.md +86 -0
- package/docs/AUTOCOMPLETE.md +136 -0
- package/docs/BACKUP.md +343 -0
- package/docs/BUILD.md +120 -0
- package/docs/BUILD_DEPLOY.md +320 -0
- package/docs/CLEANUP.md +285 -0
- package/docs/CREATE_BRANCH.md +173 -0
- package/docs/DEPLOY.md +130 -0
- package/docs/MERGE.md +253 -0
- package/docs/README.md +277 -0
- package/docs/REFACTOR.md +375 -0
- package/docs/REVIEW.md +185 -0
- package/docs/TIME_ENTRY.md +422 -0
- package/index.js +14 -0
- package/package.json +27 -9
- package/services/autocomplete.js +251 -0
- package/services/enums/actions.enum.js +12 -0
- package/services/process-commands.js +196 -27
- package/services/review.js +2 -2
- package/services/time-entry/add-task.js +50 -0
- package/services/time-entry/enums/actions.enum.js +16 -0
- package/services/time-entry/get-gitlab-activities.js +137 -0
- package/services/time-entry/get-report.js +142 -0
- package/services/time-entry/get-zoho-tasks.js +81 -0
- package/services/time-entry/log-task-hours-and-sync.js +81 -0
- package/services/time-entry/update-delete-task.js +85 -0
- package/services/time-entry/utils.js +301 -0
- package/services/utils.js +32 -15
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const readline = require('readline');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const { zohoConfig } = require('../utils');
|
|
7
|
+
|
|
8
|
+
const userHomeDir = `${os.homedir()}/.time-entry`;
|
|
9
|
+
const filePath = path.join(userHomeDir, '.zoho-config');
|
|
10
|
+
const keyMap = {
|
|
11
|
+
p: 'project',
|
|
12
|
+
project: 'project',
|
|
13
|
+
s: 'sprint',
|
|
14
|
+
sprint: 'sprint',
|
|
15
|
+
t: 'task',
|
|
16
|
+
task: 'task',
|
|
17
|
+
dt: 'date',
|
|
18
|
+
date: 'date',
|
|
19
|
+
w: 'work',
|
|
20
|
+
work: 'work',
|
|
21
|
+
du: 'duration',
|
|
22
|
+
duration: 'duration',
|
|
23
|
+
r: 'remarks',
|
|
24
|
+
remarks: 'remarks',
|
|
25
|
+
id: 'id',
|
|
26
|
+
i: 'id',
|
|
27
|
+
};
|
|
28
|
+
const contentTableHeading =
|
|
29
|
+
'| id | project | sprint | date | task | work | duration | remarks | synced |';
|
|
30
|
+
const contentTableSeparator = '| -- | -- | -- | -- | -- | -- | -- | -- | -- |';
|
|
31
|
+
|
|
32
|
+
const accessFileSync = (path) => {
|
|
33
|
+
try {
|
|
34
|
+
fs.accessSync(path, fs.constants.R_OK | fs.constants.W_OK);
|
|
35
|
+
|
|
36
|
+
return true;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const appendFileSync = (path, data) => {
|
|
42
|
+
try {
|
|
43
|
+
fs.appendFileSync(path, data);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.log(error);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const convertToTaskData = async (values) => {
|
|
49
|
+
const sprints = await getSprints({ params: { type: '2' } });
|
|
50
|
+
const data = values.reduce((acc, item) => {
|
|
51
|
+
let [key, ...itemValues] = item.split(' ');
|
|
52
|
+
let itemValue = itemValues.join(' ');
|
|
53
|
+
|
|
54
|
+
if (key.charAt(0) === '-') {
|
|
55
|
+
key = key.substring(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
switch (key) {
|
|
59
|
+
case 's':
|
|
60
|
+
case 'sprint': {
|
|
61
|
+
if (!itemValue.includes('sprint')) {
|
|
62
|
+
itemValue = `sprint ${itemValue}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
acc[keyMap[key]] = itemValue;
|
|
66
|
+
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
case 'dt':
|
|
71
|
+
case 'date': {
|
|
72
|
+
acc[keyMap[key]] = new Date(itemValue).toISOString().split('T')[0];
|
|
73
|
+
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
case 'du':
|
|
78
|
+
case 'duration': {
|
|
79
|
+
acc[keyMap[key]] = +itemValue;
|
|
80
|
+
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
default: {
|
|
85
|
+
acc[keyMap[key]] = itemValue;
|
|
86
|
+
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return acc;
|
|
92
|
+
}, {});
|
|
93
|
+
|
|
94
|
+
if (!data.project) {
|
|
95
|
+
data.project = Object.values(zohoConfig.projects).find(
|
|
96
|
+
(p) => p.value === zohoConfig.defaultProjectId,
|
|
97
|
+
)?.label;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!data.sprint) {
|
|
101
|
+
if (sprints.length > 1) {
|
|
102
|
+
await new Promise((resolve) => {
|
|
103
|
+
console.log('Multiple active sprints are available, select your task sprint.');
|
|
104
|
+
for (const [index, project] of Object.entries(sprints)) {
|
|
105
|
+
console.log(`${+index + 1}. ${project.label}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
rl.question('Enter the sprint index: ', (userInput) => {
|
|
109
|
+
data.sprint = sprints[+userInput - 1].label;
|
|
110
|
+
|
|
111
|
+
rl.close();
|
|
112
|
+
resolve(data.sprint);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
data.sprint = sprints[0].label;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return data;
|
|
121
|
+
};
|
|
122
|
+
const existsSync = (path) => {
|
|
123
|
+
return fs.existsSync(path);
|
|
124
|
+
};
|
|
125
|
+
const getHeaders = async () => {
|
|
126
|
+
return {
|
|
127
|
+
authority: 'externalusers.zohosprints.com',
|
|
128
|
+
accept: '*/*',
|
|
129
|
+
'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8,ml;q=0.7',
|
|
130
|
+
'cache-control': 'no-cache',
|
|
131
|
+
cookie: zohoConfig.cookie,
|
|
132
|
+
pragma: 'no-cache',
|
|
133
|
+
referer: `${zohoConfig.url}/workspace/4medica/client/wmoku`,
|
|
134
|
+
'sec-ch-ua': '"Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"',
|
|
135
|
+
'sec-ch-ua-mobile': '?0',
|
|
136
|
+
'sec-ch-ua-platform': '"macOS"',
|
|
137
|
+
'sec-fetch-dest': 'empty',
|
|
138
|
+
'sec-fetch-mode': 'cors',
|
|
139
|
+
'sec-fetch-site': 'same-origin',
|
|
140
|
+
'user-agent':
|
|
141
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
142
|
+
'x-requested-with': 'XMLHttpRequest',
|
|
143
|
+
'x-za-clientportalid': zohoConfig.portalId,
|
|
144
|
+
'x-za-reqsize': 'large',
|
|
145
|
+
'x-za-sessionid': zohoConfig.sessionId,
|
|
146
|
+
'x-za-source': zohoConfig.source,
|
|
147
|
+
'x-za-ui-version': 'v2',
|
|
148
|
+
'x-zcsrf-token': zohoConfig.token,
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
const getProjects = async () => {
|
|
152
|
+
const headers = await getHeaders();
|
|
153
|
+
const p = {
|
|
154
|
+
action: 'recentprojects',
|
|
155
|
+
team: '803166918',
|
|
156
|
+
};
|
|
157
|
+
const parentUrl = `${zohoConfig.url}/zsapi/team/${p.team}/projects/?action=${p.action}`;
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const response = await axios.get(parentUrl, { headers });
|
|
161
|
+
|
|
162
|
+
return Object.entries(response.data.projectJObj)
|
|
163
|
+
.map(([key, value]) => ({ value: key, label: value[0] }))
|
|
164
|
+
.sort((a, b) => (a.label < b.label ? 1 : a.label > b.label ? -1 : 0));
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error(error.message);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const getSprints = async ({ params }) => {
|
|
170
|
+
const headers = await getHeaders();
|
|
171
|
+
const p = {
|
|
172
|
+
index: params.index || 1,
|
|
173
|
+
range: params.range || 150,
|
|
174
|
+
project: params.project || zohoConfig.defaultProjectId,
|
|
175
|
+
action: 'data',
|
|
176
|
+
team: zohoConfig.team,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
if (params?.type) {
|
|
180
|
+
if (typeof params.type === 'string') {
|
|
181
|
+
p.type = params.type.split(',');
|
|
182
|
+
} else {
|
|
183
|
+
p.type = params.type;
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
p.type = ['2', '3'];
|
|
187
|
+
}
|
|
188
|
+
const parentUrl = `${zohoConfig.url}/zsapi/team/${p.team}/projects/${
|
|
189
|
+
p.project
|
|
190
|
+
}/sprints/?action=${p.action}&range=${p.range}&type=${encodeURIComponent(
|
|
191
|
+
JSON.stringify(p.type),
|
|
192
|
+
)}&index=${p.index}`;
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
const response = await axios.get(parentUrl, { headers });
|
|
196
|
+
|
|
197
|
+
return Object.entries(response.data.sprintJObj)
|
|
198
|
+
.map(([key, value]) => ({ value: key, label: value[0] }))
|
|
199
|
+
.sort((a, b) => (a.label < b.label ? 1 : a.label > b.label ? -1 : 0));
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error(error.message);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
const groupBy = (arr, key) => {
|
|
205
|
+
return arr.reduce((acc, obj) => {
|
|
206
|
+
const group = obj[key];
|
|
207
|
+
|
|
208
|
+
if (!acc[group]) {
|
|
209
|
+
acc[group] = [];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
acc[group].push(obj);
|
|
213
|
+
|
|
214
|
+
return acc;
|
|
215
|
+
}, {});
|
|
216
|
+
};
|
|
217
|
+
const mkdirSync = () => {
|
|
218
|
+
try {
|
|
219
|
+
return fs.mkdirSync(userHomeDir);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
console.log(error);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
const readFileSync = (path) => {
|
|
225
|
+
try {
|
|
226
|
+
return fs.readFileSync(path, 'utf8');
|
|
227
|
+
} catch (error) {
|
|
228
|
+
// console.log(error);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
const removeEmpty = (obj) => {
|
|
232
|
+
for (let [key, val] of Object.entries(obj)) {
|
|
233
|
+
if (val && typeof val === 'object') {
|
|
234
|
+
this.removeEmpty(val);
|
|
235
|
+
|
|
236
|
+
if (!(Object.keys(val).length || val instanceof Date)) {
|
|
237
|
+
delete obj[key];
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
if (typeof val === 'string') {
|
|
241
|
+
val = val.trim();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (val === null || val === undefined || val === '') {
|
|
245
|
+
delete obj[key];
|
|
246
|
+
} else {
|
|
247
|
+
obj[key] = val;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return obj;
|
|
253
|
+
};
|
|
254
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
255
|
+
const userConfig = async (jsonData) => {
|
|
256
|
+
return new Promise((resolve, reject) => {
|
|
257
|
+
try {
|
|
258
|
+
if (!jsonData) {
|
|
259
|
+
const data = readFileSync(filePath);
|
|
260
|
+
jsonData = JSON.parse(data);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (!Object.values(jsonData).length) {
|
|
264
|
+
throw new Error('No configurations found, try `zoho init` as first step.');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
resolve(jsonData);
|
|
268
|
+
} catch (parseError) {
|
|
269
|
+
reject(parseError);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
const writeFileSync = (path, data) => {
|
|
274
|
+
try {
|
|
275
|
+
fs.writeFileSync(path, data);
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.log(error);
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
module.exports = {
|
|
282
|
+
accessFileSync,
|
|
283
|
+
appendFileSync,
|
|
284
|
+
contentTableHeading,
|
|
285
|
+
contentTableSeparator,
|
|
286
|
+
convertToTaskData,
|
|
287
|
+
existsSync,
|
|
288
|
+
filePath,
|
|
289
|
+
getHeaders,
|
|
290
|
+
getProjects,
|
|
291
|
+
getSprints,
|
|
292
|
+
groupBy,
|
|
293
|
+
mkdirSync,
|
|
294
|
+
path,
|
|
295
|
+
readFileSync,
|
|
296
|
+
removeEmpty,
|
|
297
|
+
rl,
|
|
298
|
+
userConfig,
|
|
299
|
+
userHomeDir,
|
|
300
|
+
writeFileSync,
|
|
301
|
+
};
|
package/services/utils.js
CHANGED
|
@@ -4,10 +4,6 @@ const { ACTIONS } = require('./enums/actions.enum');
|
|
|
4
4
|
|
|
5
5
|
require('dotenv').config({ path: path.resolve(require('os').homedir(), 'Desktop/.env.nu') });
|
|
6
6
|
|
|
7
|
-
const csrfToken = process.env.CSRF_TOKEN;
|
|
8
|
-
const Cookie = process.env.COOKIE;
|
|
9
|
-
const Origin = process.env.ORIGIN;
|
|
10
|
-
const gitlabToken = process.env.GITLAB_TOKEN;
|
|
11
7
|
const mrPrompt = process.env.MR_PROMPT;
|
|
12
8
|
const mrLang = process.env.MR_LANG;
|
|
13
9
|
const mrApiUri = process.env.MR_API_URI;
|
|
@@ -15,6 +11,26 @@ const openAIKey = process.env.AI_API_KEY;
|
|
|
15
11
|
const openAIModel = process.env.AI_MODEL;
|
|
16
12
|
const backupConfig = process.env.BACKUP_CONFIG && JSON.parse(process.env.BACKUP_CONFIG);
|
|
17
13
|
const restoreConfig = process.env.RESTORE_CONFIG && JSON.parse(process.env.RESTORE_CONFIG);
|
|
14
|
+
const gitlabConfig = {
|
|
15
|
+
url: process.env.GITLAB_URL,
|
|
16
|
+
cookie: process.env.GITLAB_COOKIE,
|
|
17
|
+
xCsrfToken: process.env.GITLAB_XCSRF_TOKEN,
|
|
18
|
+
userId: process.env.GITLAB_USERID,
|
|
19
|
+
token: process.env.GITLAB_TOKEN,
|
|
20
|
+
};
|
|
21
|
+
const zohoConfig = {
|
|
22
|
+
cookie: process.env.ZOHO_COOKIE,
|
|
23
|
+
customViewId: process.env.ZOHO_CUSTOMVIEW_ID,
|
|
24
|
+
defaultProjectId: process.env.ZOHO_DEFAULt_PROJECT_ID,
|
|
25
|
+
portalId: process.env.ZOHO_PORTAL_ID,
|
|
26
|
+
projects: process.env.ZOHO_PROJECTS,
|
|
27
|
+
sessionId: process.env.ZOHO_SESSION_ID,
|
|
28
|
+
source: process.env.ZOHO_SOURCE,
|
|
29
|
+
team: process.env.ZOHO_TEAM,
|
|
30
|
+
token: process.env.ZOHO_TOKEN,
|
|
31
|
+
url: process.env.ZOHO_URI,
|
|
32
|
+
userId: process.env.ZOHO_USERID,
|
|
33
|
+
};
|
|
18
34
|
const keyMap = {
|
|
19
35
|
components: 'components',
|
|
20
36
|
c: 'components',
|
|
@@ -94,12 +110,12 @@ const buildHeaders = (url) => ({
|
|
|
94
110
|
'Accept-Language': 'en-US,en;q=0.5',
|
|
95
111
|
'Accept-Encoding': 'gzip, deflate, br',
|
|
96
112
|
Referer: `${url}/new`,
|
|
97
|
-
'X-CSRF-Token':
|
|
113
|
+
'X-CSRF-Token': gitlabConfig.xCsrfToken,
|
|
98
114
|
'X-Requested-With': 'XMLHttpRequest',
|
|
99
115
|
'Content-Type': 'application/json',
|
|
100
|
-
Origin,
|
|
116
|
+
Origin: gitlabConfig.url,
|
|
101
117
|
Connection: 'keep-alive',
|
|
102
|
-
Cookie,
|
|
118
|
+
Cookie: gitlabConfig.cookie,
|
|
103
119
|
'Sec-Fetch-Dest': 'empty',
|
|
104
120
|
'Sec-Fetch-Mode': 'cors',
|
|
105
121
|
'Sec-Fetch-Site': 'same-origin',
|
|
@@ -178,7 +194,7 @@ const generateBuildConfigs = (values = {}) => {
|
|
|
178
194
|
|
|
179
195
|
// Client config
|
|
180
196
|
if (values.components.includes('client')) {
|
|
181
|
-
configs.client.config = makeConfig(`${
|
|
197
|
+
configs.client.config = makeConfig(`${gitlabConfig.url}/cxd/${project}-client/-/pipelines`, {
|
|
182
198
|
...dataBase,
|
|
183
199
|
});
|
|
184
200
|
}
|
|
@@ -205,7 +221,7 @@ const generateBuildConfigs = (values = {}) => {
|
|
|
205
221
|
],
|
|
206
222
|
};
|
|
207
223
|
configs.backend.config = makeConfig(
|
|
208
|
-
`${
|
|
224
|
+
`${gitlabConfig.url}/cxd/${project}-backend/-/pipelines`,
|
|
209
225
|
backendData,
|
|
210
226
|
);
|
|
211
227
|
}
|
|
@@ -217,7 +233,7 @@ const generateBuildStatusConfigs = (values = {}, configs) => {
|
|
|
217
233
|
|
|
218
234
|
if (values.components.includes('client') && configs.client.buildId) {
|
|
219
235
|
configs.client.statusConfig = makeConfig(
|
|
220
|
-
`${
|
|
236
|
+
`${gitlabConfig.url}/cxd/${project}-client/-/pipelines/${configs.client.buildId}`,
|
|
221
237
|
null,
|
|
222
238
|
'get',
|
|
223
239
|
);
|
|
@@ -225,7 +241,7 @@ const generateBuildStatusConfigs = (values = {}, configs) => {
|
|
|
225
241
|
|
|
226
242
|
if (backendComps.some((c) => values.components.includes(c)) && configs.backend.buildId) {
|
|
227
243
|
configs.backend.statusConfig = makeConfig(
|
|
228
|
-
`${
|
|
244
|
+
`${gitlabConfig.url}/cxd/${project}-backend/-/pipelines/${configs.backend.buildId}`,
|
|
229
245
|
null,
|
|
230
246
|
'get',
|
|
231
247
|
);
|
|
@@ -273,7 +289,7 @@ const generateDeployConfigs = (values = {}) => {
|
|
|
273
289
|
}
|
|
274
290
|
|
|
275
291
|
const project = projectMap[values.project] || projectMap.portal;
|
|
276
|
-
const configs = makeConfig(`${
|
|
292
|
+
const configs = makeConfig(`${gitlabConfig.url}/cxd/${project}-deployment/-/pipelines`, {
|
|
277
293
|
ref: `refs/heads/${deploymentBranchMap[values.instance]}`,
|
|
278
294
|
variables_attributes,
|
|
279
295
|
});
|
|
@@ -293,7 +309,7 @@ const convertParamsToMap = async (item, type) => {
|
|
|
293
309
|
let live = false;
|
|
294
310
|
|
|
295
311
|
if (!skipCheck) {
|
|
296
|
-
if (!
|
|
312
|
+
if (!gitlabConfig.token) {
|
|
297
313
|
console.log('Configurations are missing...!');
|
|
298
314
|
return null;
|
|
299
315
|
}
|
|
@@ -301,7 +317,7 @@ const convertParamsToMap = async (item, type) => {
|
|
|
301
317
|
console.log(`Checking website status...`);
|
|
302
318
|
|
|
303
319
|
await axios
|
|
304
|
-
.get(
|
|
320
|
+
.get(gitlabConfig.url)
|
|
305
321
|
.then(() => {
|
|
306
322
|
live = true;
|
|
307
323
|
|
|
@@ -340,7 +356,6 @@ module.exports = {
|
|
|
340
356
|
generateDeployConfigs,
|
|
341
357
|
generateBuildStatusConfigs,
|
|
342
358
|
wait,
|
|
343
|
-
gitlabToken,
|
|
344
359
|
projectIdMap,
|
|
345
360
|
mrPrompt,
|
|
346
361
|
mrLang,
|
|
@@ -349,4 +364,6 @@ module.exports = {
|
|
|
349
364
|
openAIModel,
|
|
350
365
|
backupConfig,
|
|
351
366
|
restoreConfig,
|
|
367
|
+
zohoConfig,
|
|
368
|
+
gitlabConfig,
|
|
352
369
|
};
|