@waron97/prbot 2.1.0 → 2.3.0
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/.claude/settings.local.json +9 -3
- package/.prettierrc.mjs +11 -0
- package/README.md +30 -30
- package/eslint.config.mjs +16 -0
- package/index.js +327 -344
- package/package.json +33 -32
- package/src/commands/autopr.js +238 -263
- package/src/commands/changelog.js +154 -150
- package/src/commands/commit.js +146 -0
- package/src/commands/export.js +7 -0
- package/src/commands/exportPb.js +156 -0
- package/src/commands/init.js +144 -136
- package/src/commands/pr.js +81 -107
- package/src/commands/ver.js +54 -64
- package/src/config.js +4 -4
- package/src/index.js +112 -78
- package/src/lib/addons.js +4 -4
- package/src/lib/auth.js +25 -0
- package/src/lib/git.js +6 -6
package/index.js
CHANGED
|
@@ -1,393 +1,376 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { configDotenv } from "dotenv";
|
|
4
|
-
import fetch from "node-fetch";
|
|
5
|
-
import fs from "fs/promises";
|
|
2
|
+
import { execFile } from 'child_process';
|
|
6
3
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import { program } from
|
|
17
|
-
import
|
|
18
|
-
import inquirer from
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
4
|
+
appendFileSync,
|
|
5
|
+
existsSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
writeFileSync,
|
|
10
|
+
} from 'fs';
|
|
11
|
+
import fs from 'fs/promises';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { program } from 'commander';
|
|
14
|
+
import { configDotenv } from 'dotenv';
|
|
15
|
+
import inquirer from 'inquirer';
|
|
16
|
+
import fetch from 'node-fetch';
|
|
17
|
+
import omelette from 'omelette';
|
|
18
|
+
|
|
19
|
+
const CONFIG_DIR = path.join(process.env.HOME || '', '.config', 'prbot');
|
|
20
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config');
|
|
21
|
+
const COMPLETION_SCRIPT = path.join(CONFIG_DIR, 'completion.sh');
|
|
22
|
+
|
|
23
|
+
const completion = omelette('prbot <command> <module>');
|
|
24
|
+
completion.on('command', ({ reply }) => {
|
|
25
|
+
reply(['pr', 'ver', 'init']);
|
|
27
26
|
});
|
|
28
27
|
|
|
29
|
-
completion.on(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
completion.on('module', ({ before, reply }) => {
|
|
29
|
+
if (before === 'init') {
|
|
30
|
+
reply([]);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const raw = readFileSync(CONFIG_FILE, 'utf-8');
|
|
35
|
+
const match = raw.match(/^ADDONS_PATH=(.+)$/m);
|
|
36
|
+
if (!match) {
|
|
37
|
+
reply([]);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const addonsPath = match[1].trim().replace(/^~/, process.env.HOME || '');
|
|
41
|
+
reply(readdirSync(path.join(addonsPath, 'config')));
|
|
42
|
+
} catch {
|
|
43
|
+
reply([]);
|
|
40
44
|
}
|
|
41
|
-
const addonsPath = match[1].trim().replace(/^~/, process.env.HOME || "");
|
|
42
|
-
reply(readdirSync(path.join(addonsPath, "config")));
|
|
43
|
-
} catch {
|
|
44
|
-
reply([]);
|
|
45
|
-
}
|
|
46
45
|
});
|
|
47
46
|
|
|
48
47
|
completion.init();
|
|
49
48
|
|
|
50
|
-
const isCompletionMode =
|
|
51
|
-
process.argv.includes("--compbash") || process.argv.includes("--compzsh");
|
|
49
|
+
const isCompletionMode = process.argv.includes('--compbash') || process.argv.includes('--compzsh');
|
|
52
50
|
|
|
53
51
|
if (!isCompletionMode) {
|
|
54
|
-
|
|
52
|
+
configDotenv({ path: CONFIG_FILE });
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
async function getToken() {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
56
|
+
const url = process.env.KC_URL;
|
|
57
|
+
const payload = new URLSearchParams();
|
|
58
|
+
|
|
59
|
+
payload.append('username', process.env.KC_USER);
|
|
60
|
+
payload.append('password', process.env.KC_PASSWORD);
|
|
61
|
+
payload.append('client_id', process.env.KC_ID);
|
|
62
|
+
payload.append('client_secret', process.env.KC_SECRET);
|
|
63
|
+
payload.append('grant_type', 'password');
|
|
64
|
+
|
|
65
|
+
const response = await fetch(url, {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
69
|
+
},
|
|
70
|
+
body: payload.toString(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const json = await response.json();
|
|
74
|
+
return json.access_token;
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
async function getFiles(module_name, token) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
78
|
+
const url = `${process.env.RIP_URL}/ir.model/xml_prbot`;
|
|
79
|
+
const body = JSON.stringify({ module_name });
|
|
80
|
+
const headers = {
|
|
81
|
+
Authorization: `Bearer ${token}`,
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const response = await fetch(url, { method: 'POST', body, headers });
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
throw new Error(await response.text());
|
|
88
|
+
}
|
|
89
|
+
return await response.json();
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
async function main(module_name) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
let ADDONS_PATH = process.env.ADDONS_PATH;
|
|
99
|
-
if (ADDONS_PATH.startsWith("~")) {
|
|
100
|
-
ADDONS_PATH = ADDONS_PATH.replace("~", process.env.HOME);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Create out directory
|
|
104
|
-
|
|
105
|
-
// Write files temporarily and process them
|
|
106
|
-
for (const file of files) {
|
|
107
|
-
const buffer = Buffer.from(file.data, "base64");
|
|
108
|
-
|
|
109
|
-
// Read and process the file
|
|
110
|
-
let content = buffer.toString();
|
|
111
|
-
|
|
112
|
-
// Remove the last two lines
|
|
113
|
-
const lines = content.split("\n");
|
|
114
|
-
|
|
115
|
-
// Check for skipped records section appended after </odoo>
|
|
116
|
-
const odooCloseIndex = lines.findIndex((l) => l.trim() === "</odoo>");
|
|
117
|
-
if (odooCloseIndex !== -1 && odooCloseIndex < lines.length - 1) {
|
|
118
|
-
const footer = lines.slice(odooCloseIndex + 1).join("\n");
|
|
119
|
-
const skippedMatch = footer.match(/Skipped records:\s*(\d+)/);
|
|
120
|
-
if (skippedMatch && parseInt(skippedMatch[1]) > 0) {
|
|
121
|
-
throw new Error(
|
|
122
|
-
`[${file.name}] Export contains skipped records:\n${footer.trim()}`,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
const duplicatedMatch = footer.match(/Duplicated records:\s*(\d+)/);
|
|
126
|
-
if (duplicatedMatch && parseInt(duplicatedMatch[1]) > 0) {
|
|
127
|
-
throw new Error(
|
|
128
|
-
`[${file.name}] Export contains duplicated records:\n${footer.trim()}`,
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
93
|
+
const token = await getToken();
|
|
94
|
+
const files = await getFiles(module_name, token);
|
|
132
95
|
|
|
133
|
-
|
|
134
|
-
|
|
96
|
+
let ADDONS_PATH = process.env.ADDONS_PATH;
|
|
97
|
+
if (ADDONS_PATH.startsWith('~')) {
|
|
98
|
+
ADDONS_PATH = ADDONS_PATH.replace('~', process.env.HOME);
|
|
135
99
|
}
|
|
136
|
-
content = lines.join("\n");
|
|
137
100
|
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
101
|
+
// Create out directory
|
|
102
|
+
|
|
103
|
+
// Write files temporarily and process them
|
|
104
|
+
for (const file of files) {
|
|
105
|
+
const buffer = Buffer.from(file.data, 'base64');
|
|
106
|
+
|
|
107
|
+
// Read and process the file
|
|
108
|
+
let content = buffer.toString();
|
|
109
|
+
|
|
110
|
+
// Remove the last two lines
|
|
111
|
+
const lines = content.split('\n');
|
|
112
|
+
|
|
113
|
+
// Check for skipped records section appended after </odoo>
|
|
114
|
+
const odooCloseIndex = lines.findIndex((l) => l.trim() === '</odoo>');
|
|
115
|
+
if (odooCloseIndex !== -1 && odooCloseIndex < lines.length - 1) {
|
|
116
|
+
const footer = lines.slice(odooCloseIndex + 1).join('\n');
|
|
117
|
+
const skippedMatch = footer.match(/Skipped records:\s*(\d+)/);
|
|
118
|
+
if (skippedMatch && parseInt(skippedMatch[1]) > 0) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`[${file.name}] Export contains skipped records:\n${footer.trim()}`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
const duplicatedMatch = footer.match(/Duplicated records:\s*(\d+)/);
|
|
124
|
+
if (duplicatedMatch && parseInt(duplicatedMatch[1]) > 0) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`[${file.name}] Export contains duplicated records:\n${footer.trim()}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
143
130
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
131
|
+
if (lines.length > 2) {
|
|
132
|
+
lines.splice(-2);
|
|
133
|
+
}
|
|
134
|
+
content = lines.join('\n');
|
|
135
|
+
|
|
136
|
+
// Remove the bpmn_diagram field pattern
|
|
137
|
+
content = content.replace(
|
|
138
|
+
/<field name="bpmn_diagram"><!\[CDATA\[[\s\S]*?\]\]><\/field>/g,
|
|
139
|
+
''
|
|
140
|
+
);
|
|
151
141
|
|
|
152
|
-
|
|
153
|
-
|
|
142
|
+
// Determine the destination path based on filename
|
|
143
|
+
let destPath;
|
|
144
|
+
if (file.name.includes('Relazioni mancanti')) {
|
|
145
|
+
destPath = `${ADDONS_PATH}/config/${module_name}/data/workflow_missing_relations.xml`;
|
|
146
|
+
} else {
|
|
147
|
+
destPath = `${ADDONS_PATH}/config/${module_name}/data/workflow_configuration.xml`;
|
|
148
|
+
}
|
|
154
149
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
console.log(`Processed: ${file.name} -> ${destPath}`);
|
|
158
|
-
}
|
|
150
|
+
// Create destination directory if needed
|
|
151
|
+
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
153
|
+
// Write the processed file
|
|
154
|
+
await fs.writeFile(destPath, content);
|
|
155
|
+
console.log(`Processed: ${file.name} -> ${destPath}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Git operations
|
|
159
|
+
const workflowDir = path.join(ADDONS_PATH, 'config', module_name, 'data');
|
|
160
|
+
const filesToAdd = [
|
|
161
|
+
path.join(workflowDir, 'workflow_missing_relations.xml'),
|
|
162
|
+
path.join(workflowDir, 'workflow_configuration.xml'),
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
// Add files to git
|
|
166
|
+
for (const filePath of filesToAdd) {
|
|
167
|
+
await new Promise((resolve, reject) => {
|
|
168
|
+
execFile('git', ['add', filePath], { cwd: ADDONS_PATH }, (error) => {
|
|
169
|
+
if (error) reject(error);
|
|
170
|
+
else resolve();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
166
174
|
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
// Commit changes
|
|
176
|
+
const commitMessage = `[IMP][${module_name}] Update workflow`;
|
|
169
177
|
await new Promise((resolve, reject) => {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
178
|
+
execFile('git', ['commit', '-m', commitMessage], { cwd: ADDONS_PATH }, (error) => {
|
|
179
|
+
if (error) reject(error);
|
|
180
|
+
else resolve();
|
|
181
|
+
});
|
|
174
182
|
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Commit changes
|
|
178
|
-
const commitMessage = `[IMP][${module_name}] Update workflow`;
|
|
179
|
-
await new Promise((resolve, reject) => {
|
|
180
|
-
execFile(
|
|
181
|
-
"git",
|
|
182
|
-
["commit", "-m", commitMessage],
|
|
183
|
-
{ cwd: ADDONS_PATH },
|
|
184
|
-
(error) => {
|
|
185
|
-
if (error) reject(error);
|
|
186
|
-
else resolve();
|
|
187
|
-
},
|
|
188
|
-
);
|
|
189
|
-
});
|
|
190
183
|
|
|
191
|
-
|
|
184
|
+
console.log(`Committed with message: ${commitMessage}`);
|
|
192
185
|
}
|
|
193
186
|
|
|
194
187
|
async function verbot(module_name, level) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
await fs.access(manifestPath);
|
|
208
|
-
} catch {
|
|
209
|
-
manifestPath = path.join(
|
|
210
|
-
ADDONS_PATH,
|
|
211
|
-
"config",
|
|
212
|
-
module_name,
|
|
213
|
-
"__manifest__.py",
|
|
214
|
-
);
|
|
188
|
+
if (!['major', 'minor', 'patch'].includes(level)) {
|
|
189
|
+
throw new Error('Level must be one of major, minor, patch');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let ADDONS_PATH = process.env.ADDONS_PATH;
|
|
193
|
+
if (ADDONS_PATH.startsWith('~')) {
|
|
194
|
+
ADDONS_PATH = ADDONS_PATH.replace('~', process.env.HOME);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Try to find manifest file in either location
|
|
198
|
+
let manifestPath = path.join(ADDONS_PATH, module_name, '__manifest__.py');
|
|
215
199
|
try {
|
|
216
|
-
|
|
200
|
+
await fs.access(manifestPath);
|
|
217
201
|
} catch {
|
|
218
|
-
|
|
202
|
+
manifestPath = path.join(ADDONS_PATH, 'config', module_name, '__manifest__.py');
|
|
203
|
+
try {
|
|
204
|
+
await fs.access(manifestPath);
|
|
205
|
+
} catch {
|
|
206
|
+
throw new Error(`__manifest__.py not found for module ${module_name}`);
|
|
207
|
+
}
|
|
219
208
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
`"version": "${newVersion}"`,
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
// Write back the manifest
|
|
254
|
-
await fs.writeFile(manifestPath, newContent);
|
|
255
|
-
console.log(`Updated version: ${currentVersion} -> ${newVersion}`);
|
|
256
|
-
|
|
257
|
-
// Git add and commit
|
|
258
|
-
await new Promise((resolve, reject) => {
|
|
259
|
-
execFile("git", ["add", manifestPath], { cwd: ADDONS_PATH }, (error) => {
|
|
260
|
-
if (error) reject(error);
|
|
261
|
-
else resolve();
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
const commitMessage = `[VER][${module_name}] Bump`;
|
|
266
|
-
await new Promise((resolve, reject) => {
|
|
267
|
-
execFile(
|
|
268
|
-
"git",
|
|
269
|
-
["commit", "-m", commitMessage],
|
|
270
|
-
{ cwd: ADDONS_PATH },
|
|
271
|
-
(error) => {
|
|
272
|
-
if (error) reject(error);
|
|
273
|
-
else resolve();
|
|
274
|
-
},
|
|
209
|
+
|
|
210
|
+
// Read the manifest file
|
|
211
|
+
const content = await fs.readFile(manifestPath, 'utf-8');
|
|
212
|
+
|
|
213
|
+
// Find and increment version
|
|
214
|
+
const versionMatch = content.match(/"version":\s*"(15\.0\.\d+\.\d+\.\d+)"/);
|
|
215
|
+
if (!versionMatch) {
|
|
216
|
+
throw new Error('Version not found in manifest');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const currentVersion = versionMatch[1];
|
|
220
|
+
const parts = currentVersion.split('.');
|
|
221
|
+
const base = `${parts[0]}.${parts[1]}`;
|
|
222
|
+
const major = parseInt(parts[2]);
|
|
223
|
+
const minor = parseInt(parts[3]);
|
|
224
|
+
const patch = parseInt(parts[4]);
|
|
225
|
+
|
|
226
|
+
let newVersion;
|
|
227
|
+
if (level === 'patch') {
|
|
228
|
+
newVersion = `${base}.${major}.${minor}.${patch + 1}`;
|
|
229
|
+
} else if (level === 'minor') {
|
|
230
|
+
newVersion = `${base}.${major}.${minor + 1}.0`;
|
|
231
|
+
} else if (level === 'major') {
|
|
232
|
+
newVersion = `${base}.${major + 1}.0.0`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Replace only the version line
|
|
236
|
+
const newContent = content.replace(
|
|
237
|
+
`"version": "${currentVersion}"`,
|
|
238
|
+
`"version": "${newVersion}"`
|
|
275
239
|
);
|
|
276
|
-
});
|
|
277
240
|
|
|
278
|
-
|
|
241
|
+
// Write back the manifest
|
|
242
|
+
await fs.writeFile(manifestPath, newContent);
|
|
243
|
+
console.log(`Updated version: ${currentVersion} -> ${newVersion}`);
|
|
244
|
+
|
|
245
|
+
// Git add and commit
|
|
246
|
+
await new Promise((resolve, reject) => {
|
|
247
|
+
execFile('git', ['add', manifestPath], { cwd: ADDONS_PATH }, (error) => {
|
|
248
|
+
if (error) reject(error);
|
|
249
|
+
else resolve();
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const commitMessage = `[VER][${module_name}] Bump`;
|
|
254
|
+
await new Promise((resolve, reject) => {
|
|
255
|
+
execFile('git', ['commit', '-m', commitMessage], { cwd: ADDONS_PATH }, (error) => {
|
|
256
|
+
if (error) reject(error);
|
|
257
|
+
else resolve();
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
console.log(`Committed with message: ${commitMessage}`);
|
|
279
262
|
}
|
|
280
263
|
|
|
281
264
|
program
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
265
|
+
.command('pr <module>')
|
|
266
|
+
.option('-b, --bump <level>')
|
|
267
|
+
.action((module, opts) => {
|
|
268
|
+
main(module)
|
|
269
|
+
.then(() => {
|
|
270
|
+
if (opts.bump) {
|
|
271
|
+
return verbot(module, opts.bump);
|
|
272
|
+
}
|
|
273
|
+
})
|
|
274
|
+
.catch((err) => {
|
|
275
|
+
throw err;
|
|
276
|
+
});
|
|
277
|
+
});
|
|
295
278
|
|
|
296
279
|
program
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
280
|
+
.command('init')
|
|
281
|
+
.description('Create config file and install shell completion')
|
|
282
|
+
.action(async () => {
|
|
283
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
284
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
285
|
+
}
|
|
303
286
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
287
|
+
const existing = existsSync(CONFIG_FILE)
|
|
288
|
+
? Object.fromEntries(
|
|
289
|
+
readFileSync(CONFIG_FILE, 'utf-8')
|
|
290
|
+
.split('\n')
|
|
291
|
+
.flatMap((line) => {
|
|
292
|
+
const m = line.match(/^([A-Z_]+)=(.*)$/);
|
|
293
|
+
return m ? [[m[1], m[2]]] : [];
|
|
294
|
+
})
|
|
295
|
+
)
|
|
296
|
+
: {};
|
|
297
|
+
|
|
298
|
+
const answers = await inquirer.prompt([
|
|
299
|
+
{
|
|
300
|
+
type: 'input',
|
|
301
|
+
name: 'ADDONS_PATH',
|
|
302
|
+
message: 'Addons path:',
|
|
303
|
+
default: existing.ADDONS_PATH ?? '~/codebase/sorgenia/addons',
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
type: 'input',
|
|
307
|
+
name: 'KC_URL',
|
|
308
|
+
message: 'Keycloak URL:',
|
|
309
|
+
default: existing.KC_URL ?? '',
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
type: 'input',
|
|
313
|
+
name: 'KC_USER',
|
|
314
|
+
message: 'Keycloak user:',
|
|
315
|
+
default: existing.KC_USER ?? '',
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
type: 'password',
|
|
319
|
+
name: 'KC_PASSWORD',
|
|
320
|
+
message: 'Keycloak password:',
|
|
321
|
+
default: existing.KC_PASSWORD ?? '',
|
|
322
|
+
mask: '*',
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
type: 'input',
|
|
326
|
+
name: 'KC_ID',
|
|
327
|
+
message: 'Keycloak client ID:',
|
|
328
|
+
default: existing.KC_ID ?? '',
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
type: 'input',
|
|
332
|
+
name: 'KC_SECRET',
|
|
333
|
+
message: 'Keycloak client secret:',
|
|
334
|
+
default: existing.KC_SECRET ?? '',
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
type: 'input',
|
|
338
|
+
name: 'RIP_URL',
|
|
339
|
+
message: 'RIP URL:',
|
|
340
|
+
default: existing.RIP_URL ?? '',
|
|
341
|
+
},
|
|
342
|
+
]);
|
|
343
|
+
|
|
344
|
+
writeFileSync(
|
|
345
|
+
CONFIG_FILE,
|
|
346
|
+
Object.entries(answers)
|
|
347
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
348
|
+
.join('\n') + '\n'
|
|
349
|
+
);
|
|
350
|
+
console.log(`Config written to ${CONFIG_FILE}`);
|
|
351
|
+
|
|
352
|
+
writeFileSync(COMPLETION_SCRIPT, completion.generateCompletionCode());
|
|
353
|
+
console.log(`Completion script written to ${COMPLETION_SCRIPT}`);
|
|
354
|
+
|
|
355
|
+
const rcFile = path.join(process.env.HOME || '', '.bashrc');
|
|
356
|
+
const sourceLine = `source ${COMPLETION_SCRIPT}`;
|
|
357
|
+
const rcContent = existsSync(rcFile) ? readFileSync(rcFile, 'utf-8') : '';
|
|
358
|
+
if (!rcContent.includes(sourceLine)) {
|
|
359
|
+
appendFileSync(rcFile, `\n# prbot completion\n${sourceLine}\n`);
|
|
360
|
+
console.log(`Registered completion in ${rcFile} — run: source ~/.bashrc`);
|
|
361
|
+
} else {
|
|
362
|
+
console.log('Completion already registered in ~/.bashrc');
|
|
363
|
+
}
|
|
364
|
+
});
|
|
382
365
|
|
|
383
366
|
program
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
367
|
+
.command('ver <module>')
|
|
368
|
+
.option('-b, --bump <level>')
|
|
369
|
+
.action((module, opts) => {
|
|
370
|
+
if (!opts.bump) {
|
|
371
|
+
throw new Error('No bump level specified');
|
|
372
|
+
}
|
|
373
|
+
verbot(module, opts.bump);
|
|
374
|
+
});
|
|
392
375
|
|
|
393
376
|
program.parse();
|