@waron97/prbot 2.6.0 → 2.8.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/README.md CHANGED
@@ -14,13 +14,7 @@ npm install -g .
14
14
  prbot init
15
15
  ```
16
16
 
17
- Prompts for all required config values, writes them to `~/.config/prbot/config`, installs shell tab completion, and patches `~/.bashrc`. Run once, re-run anytime to update config.
18
-
19
- After first run:
20
-
21
- ```bash
22
- source ~/.bashrc
23
- ```
17
+ Prompts for all required config values and writes them to `~/.config/prbot/config`. Run once, re-run anytime to update config.
24
18
 
25
19
  ### Config keys
26
20
 
@@ -124,19 +118,20 @@ Interactive commit builder. Prompts for operation type (`[IMP]`, `[FIX]`, etc.),
124
118
  prbot commit
125
119
  ```
126
120
 
127
- ### `prbot export workflow <module>`
121
+ ### `prbot export workflow`
128
122
 
129
- Alias for `prbot pr <module>`. Fetches workflow XML and commits.
123
+ Fetches workflow XML for an interactively selected module from RIP and commits. Prompts to select the module (from `ADDONS_PATH/config/` directories) via fuzzy search.
130
124
 
131
125
  ```bash
132
- prbot export workflow config_wf_contestazione
126
+ prbot export workflow
127
+ prbot export workflow --no-commit
133
128
  ```
134
129
 
135
130
  Options:
136
131
 
137
- | Flag | Description |
138
- | -------------------- | ------------------------------------------------------------------------- |
139
- | `-b, --bump <level>` | Also bump manifest version after commit. Level: `major`, `minor`, `patch` |
132
+ | Flag | Description |
133
+ | ------------- | ------------------------ |
134
+ | `--no-commit` | Skip the git commit step |
140
135
 
141
136
  ### `prbot export pb`
142
137
 
@@ -168,9 +163,24 @@ Options:
168
163
  | ------------- | ------------------------ |
169
164
  | `--no-commit` | Skip the git commit step |
170
165
 
166
+ ### `prbot export email-templates`
167
+
168
+ Fetches email templates for an interactively selected workflow from RIP and writes them as `ADDONS_PATH/config/<module>/data/mail_templates.xml`. Prompts first for the module (from `ADDONS_PATH/config/` directories), then for the workflow. Both prompts support fuzzy search.
169
+
170
+ ```bash
171
+ prbot export email-templates
172
+ prbot export email-templates --no-commit
173
+ ```
174
+
175
+ Options:
176
+
177
+ | Flag | Description |
178
+ | ------------- | ------------------------ |
179
+ | `--no-commit` | Skip the git commit step |
180
+
171
181
  ### `prbot init`
172
182
 
173
- Interactive setup: writes `~/.config/prbot/config` and installs shell completion.
183
+ Interactive setup: writes `~/.config/prbot/config`.
174
184
 
175
185
  ### `prbot update`
176
186
 
@@ -180,10 +190,3 @@ Reinstalls the latest published version from npm.
180
190
  prbot update
181
191
  ```
182
192
 
183
- ## Tab completion
184
-
185
- After `prbot init` and sourcing `~/.bashrc`, `<module>` arguments autocomplete from directories in `ADDONS_PATH/config/`.
186
-
187
- ```
188
- prbot pr config_wf_<TAB> # lists all workflow modules
189
- ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waron97/prbot",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -73,6 +73,10 @@ function buildPrDescription(taskIds, jiras) {
73
73
  async function createDevopsPR(branch, title, description) {
74
74
  const { DEVOPS_ORG, DEVOPS_PROJECT, DEVOPS_REPO, AUTOPR_TARGET_BRANCH } = process.env;
75
75
  const apiUrl = `https://dev.azure.com/${DEVOPS_ORG}/${DEVOPS_PROJECT}/_apis/git/repositories/${DEVOPS_REPO}/pullrequests?api-version=7.0`;
76
+ const reviewers = process.env.AUTOPR_REQUIRED_REVIEWER_ID
77
+ ? [{ id: process.env.AUTOPR_REQUIRED_REVIEWER_ID, isRequired: true }]
78
+ : [];
79
+
76
80
  const res = await fetch(apiUrl, {
77
81
  method: 'POST',
78
82
  headers: devopsHeaders(),
@@ -82,6 +86,7 @@ async function createDevopsPR(branch, title, description) {
82
86
  isDraft: true,
83
87
  sourceRefName: `refs/heads/${branch}`,
84
88
  targetRefName: `refs/heads/${AUTOPR_TARGET_BRANCH}`,
89
+ reviewers,
85
90
  }),
86
91
  });
87
92
  const data = await res.json();
@@ -9,7 +9,7 @@ function buildRefString(tridents, jiras, prNumber) {
9
9
  const refs = [];
10
10
 
11
11
  if (tridents && tridents.length > 0) {
12
- refs.push(`Trident ${tridents.map((t) => `#${t}`).join(', #')}`);
12
+ refs.push(`Trident ${tridents.map((t) => `#${t}`).join(', ')}`);
13
13
  }
14
14
 
15
15
  if (jiras && jiras.length > 0) {
@@ -1,9 +1,10 @@
1
1
  import { exportPb } from './exportPb.js';
2
2
  import { exportImperex } from './exportImperex.js';
3
3
  import { exportEmailTemplates } from './exportEmailTemplates.js';
4
+ import { exportWorkflow } from './exportWorkflow.js';
4
5
 
5
6
  function exportRip() {
6
7
  console.log('Not implemented yet.');
7
8
  }
8
9
 
9
- export { exportPb, exportRip, exportImperex, exportEmailTemplates };
10
+ export { exportPb, exportRip, exportImperex, exportEmailTemplates, exportWorkflow };
@@ -0,0 +1,49 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import search from '@inquirer/search';
4
+ import { select } from '@inquirer/prompts';
5
+ import { resolveAddonsPath } from '../lib/addons.js';
6
+ import { fuzzyMatch } from '../lib/fuzzy.js';
7
+ import { runPr } from './pr.js';
8
+ import { verbot } from './ver.js';
9
+
10
+ async function getModuleChoices() {
11
+ const ADDONS_PATH = resolveAddonsPath(process.env.ADDONS_PATH);
12
+ const configDir = path.join(ADDONS_PATH, 'config');
13
+ const entries = await fs.readdir(configDir, { withFileTypes: true });
14
+ return entries
15
+ .filter((e) => e.isDirectory())
16
+ .map((e) => ({ name: e.name, value: e.name }));
17
+ }
18
+
19
+ async function exportWorkflow(opts) {
20
+ const moduleChoices = await getModuleChoices();
21
+ const module = await search({
22
+ message: 'Select module:',
23
+ source: async (input) => {
24
+ if (!input) return moduleChoices;
25
+ return moduleChoices.filter((c) => fuzzyMatch(c.name, input));
26
+ },
27
+ });
28
+
29
+ await runPr(module, opts);
30
+
31
+ let bumpLevel = opts.bump;
32
+ if (!bumpLevel) {
33
+ bumpLevel = await select({
34
+ message: 'Bump version?',
35
+ choices: [
36
+ { name: 'No bump', value: 'none' },
37
+ { name: 'Patch', value: 'patch' },
38
+ { name: 'Minor', value: 'minor' },
39
+ { name: 'Major', value: 'major' },
40
+ ],
41
+ });
42
+ }
43
+
44
+ if (bumpLevel && bumpLevel !== 'none') {
45
+ await verbot(module, bumpLevel);
46
+ }
47
+ }
48
+
49
+ export { exportWorkflow };
@@ -1,9 +1,8 @@
1
- import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
- import path from 'path';
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
3
2
  import inquirer from 'inquirer';
4
- import { COMPLETION_SCRIPT, CONFIG_DIR, CONFIG_FILE } from '../config.js';
3
+ import { CONFIG_DIR, CONFIG_FILE } from '../config.js';
5
4
 
6
- async function init(completion) {
5
+ async function init() {
7
6
  if (!existsSync(CONFIG_DIR)) {
8
7
  mkdirSync(CONFIG_DIR, { recursive: true });
9
8
  }
@@ -137,19 +136,6 @@ async function init(completion) {
137
136
  .join('\n') + '\n'
138
137
  );
139
138
  console.log(`Config written to ${CONFIG_FILE}`);
140
-
141
- writeFileSync(COMPLETION_SCRIPT, completion.generateCompletionCode());
142
- console.log(`Completion script written to ${COMPLETION_SCRIPT}`);
143
-
144
- const rcFile = path.join(process.env.HOME || '', '.bashrc');
145
- const sourceLine = `source ${COMPLETION_SCRIPT}`;
146
- const rcContent = existsSync(rcFile) ? readFileSync(rcFile, 'utf-8') : '';
147
- if (!rcContent.includes(sourceLine)) {
148
- appendFileSync(rcFile, `\n# prbot completion\n${sourceLine}\n`);
149
- console.log(`Registered completion in ${rcFile} — run: source ~/.bashrc`);
150
- } else {
151
- console.log('Completion already registered in ~/.bashrc');
152
- }
153
139
  }
154
140
 
155
141
  export { init };
@@ -20,7 +20,7 @@ async function getFiles(module_name, token) {
20
20
  return await response.json();
21
21
  }
22
22
 
23
- async function main(module_name) {
23
+ async function runPr(module_name, opts = {}) {
24
24
  const token = await getToken();
25
25
  const files = await getFiles(module_name, token);
26
26
 
@@ -69,6 +69,8 @@ async function main(module_name) {
69
69
  console.log(`Processed: ${file.name} -> ${destPath}`);
70
70
  }
71
71
 
72
+ if (opts.commit === false) return;
73
+
72
74
  const workflowDir = path.join(ADDONS_PATH, 'config', module_name, 'data');
73
75
  const filesToAdd = [
74
76
  path.join(workflowDir, 'workflow_missing_relations.xml'),
@@ -95,4 +97,8 @@ async function main(module_name) {
95
97
  console.log(`Committed with message: ${commitMessage}`);
96
98
  }
97
99
 
98
- export { main };
100
+ async function main(module_name) {
101
+ return runPr(module_name);
102
+ }
103
+
104
+ export { main, runPr };
package/src/config.js CHANGED
@@ -2,6 +2,5 @@ import path from 'path';
2
2
 
3
3
  const CONFIG_DIR = path.join(process.env.HOME || '', '.config', 'prbot');
4
4
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config');
5
- const COMPLETION_SCRIPT = path.join(CONFIG_DIR, 'completion.sh');
6
5
 
7
- export { CONFIG_DIR, CONFIG_FILE, COMPLETION_SCRIPT };
6
+ export { CONFIG_DIR, CONFIG_FILE };
package/src/index.js CHANGED
@@ -1,67 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { readdirSync, readFileSync } from 'fs';
3
2
  import { execFile } from 'child_process';
4
- import path from 'path';
5
3
  import { program } from 'commander';
6
4
  import { configDotenv } from 'dotenv';
7
- import omelette from 'omelette';
8
5
  import { autopr } from './commands/autopr.js';
9
6
  import { changelog } from './commands/changelog.js';
10
7
  import { commit } from './commands/commit.js';
11
- import { exportPb, exportRip, exportImperex, exportEmailTemplates } from './commands/export.js';
8
+ import { exportPb, exportRip, exportImperex, exportEmailTemplates, exportWorkflow } from './commands/export.js';
12
9
  import { init } from './commands/init.js';
13
10
  import { main as prMain } from './commands/pr.js';
14
11
  import { verbot } from './commands/ver.js';
15
12
  import { CONFIG_FILE } from './config.js';
16
13
 
17
- const EXPORT_SUBCOMMANDS = ['workflow', 'email-templates', 'pb', 'imperex', 'rip'];
18
-
19
- function replyModules(reply) {
20
- try {
21
- const raw = readFileSync(CONFIG_FILE, 'utf-8');
22
- const match = raw.match(/^ADDONS_PATH=(.+)$/m);
23
- if (!match) { reply([]); return; }
24
- const addonsPath = match[1].trim().replace(/^~/, process.env.HOME || '');
25
- reply(readdirSync(path.join(addonsPath, 'config')));
26
- } catch {
27
- reply([]);
28
- }
29
- }
30
-
31
- const completion = omelette('prbot <command> <subOrModule> <module>');
32
- completion.on('command', ({ reply }) => {
33
- reply(['pr', 'ver', 'init', 'changelog', 'autopr', 'commit', 'export']);
34
- });
35
-
36
- // 2nd token: export subcommands or module (for non-export commands)
37
- completion.on('subOrModule', ({ before, reply }) => {
38
- if (before === 'export') {
39
- reply(EXPORT_SUBCOMMANDS);
40
- return;
41
- }
42
- if (['init', 'changelog', 'autopr'].includes(before)) {
43
- reply([]);
44
- return;
45
- }
46
- replyModules(reply);
47
- });
48
-
49
- // 3rd token: module (only relevant for export subcommands that take one)
50
- completion.on('module', ({ before, reply }) => {
51
- if (['workflow'].includes(before)) {
52
- replyModules(reply);
53
- } else {
54
- reply([]);
55
- }
56
- });
57
-
58
- completion.init();
59
-
60
- const isCompletionMode = process.argv.includes('--compbash') || process.argv.includes('--compzsh');
61
-
62
- if (!isCompletionMode) {
63
- configDotenv({ path: CONFIG_FILE });
64
- }
14
+ configDotenv({ path: CONFIG_FILE });
65
15
 
66
16
  program
67
17
  .command('pr <module>')
@@ -90,9 +40,9 @@ program
90
40
 
91
41
  program
92
42
  .command('init')
93
- .description('Create config file and install shell completion')
43
+ .description('Create config file')
94
44
  .action(() => {
95
- init(completion);
45
+ init();
96
46
  });
97
47
 
98
48
  const collect = (val, prev) => [...(prev ?? []), val];
@@ -130,18 +80,13 @@ program.command('commit').action((opts) => {
130
80
  const exportCmd = program.command('export');
131
81
 
132
82
  exportCmd
133
- .command('workflow <module>')
134
- .option('-b, --bump <level>')
135
- .action((module, opts) => {
136
- prMain(module)
137
- .then(() => {
138
- if (opts.bump) {
139
- return verbot(module, opts.bump);
140
- }
141
- })
142
- .catch((err) => {
143
- throw err;
144
- });
83
+ .command('workflow')
84
+ .option('--no-commit')
85
+ .option('-b, --bump <level>', 'Version bump level (patch, minor, major)')
86
+ .action((opts) => {
87
+ exportWorkflow(opts).catch((err) => {
88
+ throw err;
89
+ });
145
90
  });
146
91
 
147
92
  exportCmd.command('rip').action(() => exportRip());
@@ -1,11 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(node *)",
5
- "Bash(npm install *)",
6
- "Bash(npx eslint *)",
7
- "Bash(npx prettier *)",
8
- "Bash(npm ls *)"
9
- ]
10
- }
11
- }
package/index.js DELETED
@@ -1,376 +0,0 @@
1
- #!/usr/bin/env node
2
- import { execFile } from 'child_process';
3
- import {
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']);
26
- });
27
-
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([]);
44
- }
45
- });
46
-
47
- completion.init();
48
-
49
- const isCompletionMode = process.argv.includes('--compbash') || process.argv.includes('--compzsh');
50
-
51
- if (!isCompletionMode) {
52
- configDotenv({ path: CONFIG_FILE });
53
- }
54
-
55
- async function getToken() {
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;
75
- }
76
-
77
- async function getFiles(module_name, token) {
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();
90
- }
91
-
92
- async function main(module_name) {
93
- const token = await getToken();
94
- const files = await getFiles(module_name, token);
95
-
96
- let ADDONS_PATH = process.env.ADDONS_PATH;
97
- if (ADDONS_PATH.startsWith('~')) {
98
- ADDONS_PATH = ADDONS_PATH.replace('~', process.env.HOME);
99
- }
100
-
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
- }
130
-
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
- );
141
-
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
- }
149
-
150
- // Create destination directory if needed
151
- await fs.mkdir(path.dirname(destPath), { recursive: true });
152
-
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
- }
174
-
175
- // Commit changes
176
- const commitMessage = `[IMP][${module_name}] Update workflow`;
177
- await new Promise((resolve, reject) => {
178
- execFile('git', ['commit', '-m', commitMessage], { cwd: ADDONS_PATH }, (error) => {
179
- if (error) reject(error);
180
- else resolve();
181
- });
182
- });
183
-
184
- console.log(`Committed with message: ${commitMessage}`);
185
- }
186
-
187
- async function verbot(module_name, level) {
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');
199
- try {
200
- await fs.access(manifestPath);
201
- } catch {
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
- }
208
- }
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}"`
239
- );
240
-
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}`);
262
- }
263
-
264
- program
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
- });
278
-
279
- program
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
- }
286
-
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
- });
365
-
366
- program
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
- });
375
-
376
- program.parse();