@waron97/prbot 3.5.0 → 3.7.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/package.json +1 -1
- package/src/commands/autopr.js +37 -66
- package/src/commands/doc.js +93 -0
- package/src/commands/exportEmailTemplates.js +1 -0
- package/src/commands/init.js +2 -1
- package/src/index.js +12 -0
- package/src/lib/addons.js +11 -4
- package/src/lib/html.js +117 -0
- package/src/lib/trident.js +34 -0
package/package.json
CHANGED
package/src/commands/autopr.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
2
|
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
3
4
|
import search from '@inquirer/search';
|
|
4
5
|
import inquirer from 'inquirer';
|
|
5
6
|
import fetch from 'node-fetch';
|
|
@@ -7,6 +8,7 @@ import { resolveAddonsPath } from '../lib/addons.js';
|
|
|
7
8
|
import { fuzzyMatch } from '../lib/fuzzy.js';
|
|
8
9
|
import { execGit } from '../lib/git.js';
|
|
9
10
|
import { log } from '../lib/logger.js';
|
|
11
|
+
import { tridentRpc } from '../lib/trident.js';
|
|
10
12
|
import {
|
|
11
13
|
appendPrToLine,
|
|
12
14
|
appendRefsToLine,
|
|
@@ -27,42 +29,11 @@ function devopsHeaders() {
|
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
async function fetchTask(taskId) {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
jsonrpc: '2.0',
|
|
33
|
-
method: 'call',
|
|
34
|
-
id: 1,
|
|
35
|
-
params: {
|
|
36
|
-
service: 'object',
|
|
37
|
-
method: 'execute_kw',
|
|
38
|
-
args: [
|
|
39
|
-
process.env.TRIDENT_DB,
|
|
40
|
-
parseInt(process.env.TRIDENT_UID, 10),
|
|
41
|
-
process.env.TRIDENT_TOKEN,
|
|
42
|
-
'project.task',
|
|
43
|
-
'read',
|
|
44
|
-
[[parseInt(taskId, 10)]],
|
|
45
|
-
{
|
|
46
|
-
fields: [
|
|
47
|
-
'name',
|
|
48
|
-
'x_subpackage_id',
|
|
49
|
-
'x_workflow',
|
|
50
|
-
'x_cluster_id',
|
|
51
|
-
'x_release_checklist',
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
const res = await fetch(url, {
|
|
58
|
-
method: 'POST',
|
|
59
|
-
headers: { 'Content-Type': 'application/json' },
|
|
60
|
-
body: JSON.stringify(body),
|
|
32
|
+
const result = await tridentRpc('project.task', 'read', [[parseInt(taskId, 10)]], {
|
|
33
|
+
fields: ['name', 'x_subpackage_id', 'x_workflow', 'x_cluster_id', 'x_release_checklist'],
|
|
61
34
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (!data.result || !data.result[0]) throw new Error(`Task ${taskId} not found`);
|
|
65
|
-
return data.result[0];
|
|
35
|
+
if (!result || !result[0]) throw new Error(`Task ${taskId} not found`);
|
|
36
|
+
return result[0];
|
|
66
37
|
}
|
|
67
38
|
|
|
68
39
|
function buildPrDescription(taskIds, jiras) {
|
|
@@ -124,30 +95,10 @@ async function createDevopsPR(branch, title, description) {
|
|
|
124
95
|
async function appendChecklistPrLink(taskId, currentChecklist, prUrl) {
|
|
125
96
|
const link = `<a href="${prUrl}">${prUrl}</a><br/>`;
|
|
126
97
|
const updated = currentChecklist ? `${currentChecklist}\n${link}` : link;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
body: JSON.stringify({
|
|
132
|
-
jsonrpc: '2.0',
|
|
133
|
-
method: 'call',
|
|
134
|
-
id: 2,
|
|
135
|
-
params: {
|
|
136
|
-
service: 'object',
|
|
137
|
-
method: 'execute_kw',
|
|
138
|
-
args: [
|
|
139
|
-
process.env.TRIDENT_DB,
|
|
140
|
-
parseInt(process.env.TRIDENT_UID, 10),
|
|
141
|
-
process.env.TRIDENT_TOKEN,
|
|
142
|
-
'project.task',
|
|
143
|
-
'write',
|
|
144
|
-
[[parseInt(taskId, 10)], { x_release_checklist: updated }],
|
|
145
|
-
],
|
|
146
|
-
},
|
|
147
|
-
}),
|
|
148
|
-
});
|
|
149
|
-
const data = await res.json();
|
|
150
|
-
if (data.error) throw new Error(`Trident write error: ${JSON.stringify(data.error)}`);
|
|
98
|
+
await tridentRpc('project.task', 'write', [
|
|
99
|
+
[parseInt(taskId, 10)],
|
|
100
|
+
{ x_release_checklist: updated },
|
|
101
|
+
]);
|
|
151
102
|
}
|
|
152
103
|
|
|
153
104
|
function scoreSections(sections, candidates) {
|
|
@@ -268,6 +219,11 @@ async function autoprAmend(options) {
|
|
|
268
219
|
}
|
|
269
220
|
|
|
270
221
|
async function autopr(options) {
|
|
222
|
+
if (options.worktree && options.amend) {
|
|
223
|
+
throw new Error(
|
|
224
|
+
'--worktree cannot be combined with --amend (amend operates on the already-checked-out branch)'
|
|
225
|
+
);
|
|
226
|
+
}
|
|
271
227
|
if (options.amend) return autoprAmend(options);
|
|
272
228
|
|
|
273
229
|
const ADDONS_PATH = resolveAddonsPath(process.env.ADDONS_PATH);
|
|
@@ -313,9 +269,20 @@ async function autopr(options) {
|
|
|
313
269
|
}
|
|
314
270
|
}
|
|
315
271
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
272
|
+
let repoRoot = ADDONS_PATH;
|
|
273
|
+
if (options.worktree) {
|
|
274
|
+
const worktreePath =
|
|
275
|
+
typeof options.worktree === 'string'
|
|
276
|
+
? path.resolve(options.worktree)
|
|
277
|
+
: path.join(path.dirname(ADDONS_PATH), `${path.basename(ADDONS_PATH)}-${branch}`);
|
|
278
|
+
await execGit(['worktree', 'add', worktreePath, '-b', branch], ADDONS_PATH);
|
|
279
|
+
log(`Worktree created: ${worktreePath}`);
|
|
280
|
+
repoRoot = worktreePath;
|
|
281
|
+
} else {
|
|
282
|
+
await execGit(['checkout', '-b', branch], ADDONS_PATH);
|
|
283
|
+
log(`Branch created: ${branch}`);
|
|
284
|
+
}
|
|
285
|
+
await execGit(['push', '-u', 'origin', branch], repoRoot);
|
|
319
286
|
|
|
320
287
|
const prTitle = options.name ?? tasks[0]?.name ?? branch;
|
|
321
288
|
const prDescription = buildPrDescription(ids, options.jira ?? []);
|
|
@@ -363,13 +330,17 @@ async function autopr(options) {
|
|
|
363
330
|
lines.splice(endLine + 1, 0, newEntry);
|
|
364
331
|
}
|
|
365
332
|
|
|
366
|
-
await fs.writeFile(
|
|
333
|
+
await fs.writeFile(`${repoRoot}/CHANGELOG.md`, lines.join('\n'));
|
|
367
334
|
log('Changelog entry written');
|
|
368
335
|
|
|
369
|
-
await execGit(['add', 'CHANGELOG.md'],
|
|
370
|
-
await execGit(['commit', '-m', '[DOC][CHANGELOG] Changelog'],
|
|
371
|
-
await execGit(['push'],
|
|
336
|
+
await execGit(['add', 'CHANGELOG.md'], repoRoot);
|
|
337
|
+
await execGit(['commit', '-m', '[DOC][CHANGELOG] Changelog'], repoRoot);
|
|
338
|
+
await execGit(['push'], repoRoot);
|
|
372
339
|
log('Changelog committed and pushed');
|
|
340
|
+
|
|
341
|
+
if (repoRoot !== ADDONS_PATH) {
|
|
342
|
+
log(`\nContinue working in: ${repoRoot}`);
|
|
343
|
+
}
|
|
373
344
|
}
|
|
374
345
|
|
|
375
346
|
export { autopr };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { htmlToMarkdown } from '../lib/html.js';
|
|
4
|
+
import { log, warn } from '../lib/logger.js';
|
|
5
|
+
import { tridentRpc } from '../lib/trident.js';
|
|
6
|
+
|
|
7
|
+
async function fetchTaskDoc(taskId) {
|
|
8
|
+
const id = parseInt(taskId, 10);
|
|
9
|
+
const [task] = await tridentRpc('project.task', 'read', [[id]], {
|
|
10
|
+
fields: ['name', 'description'],
|
|
11
|
+
});
|
|
12
|
+
if (!task) throw new Error(`Task ${taskId} not found`);
|
|
13
|
+
|
|
14
|
+
const attachments = await tridentRpc(
|
|
15
|
+
'ir.attachment',
|
|
16
|
+
'search_read',
|
|
17
|
+
[
|
|
18
|
+
[
|
|
19
|
+
['res_model', '=', 'project.task'],
|
|
20
|
+
['res_id', '=', id],
|
|
21
|
+
],
|
|
22
|
+
],
|
|
23
|
+
{ fields: ['name', 'datas', 'mimetype'] }
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return { task, attachments };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Strips path separators from an Odoo attachment name and de-dupes against
|
|
30
|
+
// names already written into the same folder.
|
|
31
|
+
function safeFilename(name, usedNames) {
|
|
32
|
+
const cleaned = (name || 'attachment').replace(/[/\\]/g, '_').trim() || 'attachment';
|
|
33
|
+
if (!usedNames.has(cleaned)) {
|
|
34
|
+
usedNames.add(cleaned);
|
|
35
|
+
return cleaned;
|
|
36
|
+
}
|
|
37
|
+
const ext = path.extname(cleaned);
|
|
38
|
+
const base = cleaned.slice(0, cleaned.length - ext.length);
|
|
39
|
+
let i = 2;
|
|
40
|
+
let candidate = `${base} (${i})${ext}`;
|
|
41
|
+
while (usedNames.has(candidate)) {
|
|
42
|
+
i += 1;
|
|
43
|
+
candidate = `${base} (${i})${ext}`;
|
|
44
|
+
}
|
|
45
|
+
usedNames.add(candidate);
|
|
46
|
+
return candidate;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function writeTaskDoc(taskId, { task, attachments }) {
|
|
50
|
+
const dirName = `trident_${taskId}`;
|
|
51
|
+
const dir = path.join(process.cwd(), dirName);
|
|
52
|
+
await fs.mkdir(dir, { recursive: true });
|
|
53
|
+
|
|
54
|
+
const usedNames = new Set();
|
|
55
|
+
const writtenFiles = [];
|
|
56
|
+
for (const att of attachments) {
|
|
57
|
+
if (!att.datas) {
|
|
58
|
+
warn(`Warning: skipping attachment "${att.name}" (no downloadable content)`);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const filename = safeFilename(att.name, usedNames);
|
|
62
|
+
await fs.writeFile(path.join(dir, filename), Buffer.from(att.datas, 'base64'));
|
|
63
|
+
writtenFiles.push(filename);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const taskUrl = `${process.env.TRIDENT_URL}/odoo/my-tasks/${taskId}`;
|
|
67
|
+
const lines = [`# ${task.name}`, '', taskUrl, ''];
|
|
68
|
+
const body = htmlToMarkdown(task.description);
|
|
69
|
+
if (body) lines.push(body, '');
|
|
70
|
+
|
|
71
|
+
lines.push('## Attachments');
|
|
72
|
+
if (writtenFiles.length === 0) {
|
|
73
|
+
lines.push('', '_None_');
|
|
74
|
+
} else {
|
|
75
|
+
lines.push('', ...writtenFiles.map((f) => `- [${f}](./${f})`));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await fs.writeFile(path.join(dir, `${dirName}.md`), lines.join('\n') + '\n');
|
|
79
|
+
return dir;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function doc(opts) {
|
|
83
|
+
const ids = opts.trident ?? [];
|
|
84
|
+
if (ids.length === 0) throw new Error('No Trident id: provide -t <id>');
|
|
85
|
+
|
|
86
|
+
for (const id of ids) {
|
|
87
|
+
const data = await fetchTaskDoc(id);
|
|
88
|
+
const dir = await writeTaskDoc(id, data);
|
|
89
|
+
log(`Wrote ${dir}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export { doc };
|
|
@@ -73,6 +73,7 @@ function generateXml(templates) {
|
|
|
73
73
|
<field name="subject">${escapeXml(t.subject)}</field>
|
|
74
74
|
<field name="email_from">${escapeXml(t.email_from)}</field>
|
|
75
75
|
<field name="email_to">${escapeXml(t.email_to)}</field>
|
|
76
|
+
<field name="lang">${escapeXml(t.lang)}</field>
|
|
76
77
|
<field name="body_html" type="html">
|
|
77
78
|
${sanitizeBodyHtml(t.body_html)}
|
|
78
79
|
</field>
|
package/src/commands/init.js
CHANGED
|
@@ -23,7 +23,8 @@ async function init() {
|
|
|
23
23
|
{
|
|
24
24
|
type: 'input',
|
|
25
25
|
name: 'ADDONS_PATH',
|
|
26
|
-
message:
|
|
26
|
+
message:
|
|
27
|
+
"Addons path ('.' or blank = use the repo in the current directory, e.g. a worktree):",
|
|
27
28
|
default: existing.ADDONS_PATH ?? '~/codebase/sorgenia/addons',
|
|
28
29
|
},
|
|
29
30
|
{
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { configDotenv } from 'dotenv';
|
|
|
5
5
|
import { autopr } from './commands/autopr.js';
|
|
6
6
|
import { changelog } from './commands/changelog.js';
|
|
7
7
|
import { commit } from './commands/commit.js';
|
|
8
|
+
import { doc } from './commands/doc.js';
|
|
8
9
|
import {
|
|
9
10
|
exportEmailTemplates,
|
|
10
11
|
exportImperex,
|
|
@@ -135,6 +136,10 @@ program
|
|
|
135
136
|
.option('-b, --branch <name>', 'Branch name (default: autopr_<taskId>)')
|
|
136
137
|
.option('-n, --name <text>', 'PR title (default: task name from Odoo)')
|
|
137
138
|
.option('--amend', 'Amend existing PR on current branch with new trident/jira refs')
|
|
139
|
+
.option(
|
|
140
|
+
'--worktree [path]',
|
|
141
|
+
'Create the branch in a new git worktree instead of switching the current checkout; optional path overrides the default sibling directory'
|
|
142
|
+
)
|
|
138
143
|
.action(async (opts) => {
|
|
139
144
|
await autopr(opts);
|
|
140
145
|
});
|
|
@@ -143,6 +148,13 @@ program.command('commit').action(async (opts) => {
|
|
|
143
148
|
await commit(opts);
|
|
144
149
|
});
|
|
145
150
|
|
|
151
|
+
program
|
|
152
|
+
.command('doc')
|
|
153
|
+
.option('-t, --trident <id>', 'Trident task IDs (repeatable)', collect)
|
|
154
|
+
.action(async (opts) => {
|
|
155
|
+
await doc(opts);
|
|
156
|
+
});
|
|
157
|
+
|
|
146
158
|
const exportCmd = program.command('export');
|
|
147
159
|
|
|
148
160
|
withQuiet(
|
package/src/lib/addons.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
function resolveAddonsPath(addonsPath) {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
function resolveAddonsPath(addonsPath = process.env.ADDONS_PATH) {
|
|
2
|
+
const value = (addonsPath ?? '').trim();
|
|
3
|
+
// Unset, empty, or the explicit "." sentinel => operate on the repo in
|
|
4
|
+
// the current working directory (e.g. a git worktree), instead of a
|
|
5
|
+
// fixed global checkout.
|
|
6
|
+
if (value === '' || value === '.') {
|
|
7
|
+
return process.cwd();
|
|
4
8
|
}
|
|
5
|
-
|
|
9
|
+
if (value.startsWith('~')) {
|
|
10
|
+
return value.replace('~', process.env.HOME);
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
6
13
|
}
|
|
7
14
|
|
|
8
15
|
export { resolveAddonsPath };
|
package/src/lib/html.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Small, dependency-free HTML→markdown converter. Not a general-purpose HTML
|
|
2
|
+
// parser — it's sized to the markup Odoo actually produces for `project.task`
|
|
3
|
+
// description fields (paragraphs, line breaks, bold/italic, links, lists,
|
|
4
|
+
// inline images), which is enough to render usefully in a .md file. Anything
|
|
5
|
+
// outside that (tables, nested lists, styled spans, ...) is stripped down to
|
|
6
|
+
// its plain text rather than mis-rendered.
|
|
7
|
+
|
|
8
|
+
function decodeEntities(str) {
|
|
9
|
+
return str
|
|
10
|
+
.replace(/ /gi, ' ')
|
|
11
|
+
.replace(/&/gi, '&')
|
|
12
|
+
.replace(/</gi, '<')
|
|
13
|
+
.replace(/>/gi, '>')
|
|
14
|
+
.replace(/"/gi, '"')
|
|
15
|
+
.replace(/'/g, "'")
|
|
16
|
+
.replace(/'/gi, "'");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function htmlToMarkdown(html) {
|
|
20
|
+
if (!html) return '';
|
|
21
|
+
|
|
22
|
+
let out = '';
|
|
23
|
+
let lastIndex = 0;
|
|
24
|
+
let match;
|
|
25
|
+
const listStack = []; // { type: 'ul' | 'ol', index: number }
|
|
26
|
+
const linkStack = []; // pending href for the currently-open <a>
|
|
27
|
+
|
|
28
|
+
// Raw text between tags: collapse the source's own whitespace/indentation
|
|
29
|
+
// into single spaces. Paragraph/line breaks are produced by the tag
|
|
30
|
+
// handling below, not by whitespace in the source.
|
|
31
|
+
function appendText(text) {
|
|
32
|
+
const cleaned = text.replace(/\s+/g, ' ');
|
|
33
|
+
if (cleaned.trim() === '') return;
|
|
34
|
+
out += cleaned;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const tagRe = /<(\/?)([a-zA-Z0-9]+)([^>]*)>/g;
|
|
38
|
+
while ((match = tagRe.exec(html)) !== null) {
|
|
39
|
+
const [, closing, rawTag, attrs] = match;
|
|
40
|
+
const tag = rawTag.toLowerCase();
|
|
41
|
+
appendText(html.slice(lastIndex, match.index));
|
|
42
|
+
lastIndex = tagRe.lastIndex;
|
|
43
|
+
const isClosing = closing === '/';
|
|
44
|
+
|
|
45
|
+
switch (tag) {
|
|
46
|
+
case 'br':
|
|
47
|
+
out += '\n';
|
|
48
|
+
break;
|
|
49
|
+
case 'p':
|
|
50
|
+
case 'div':
|
|
51
|
+
// Odoo commonly wraps list-item text in a <p> (<li><p>...</p></li>);
|
|
52
|
+
// inside a list, let <li> alone own the line breaks.
|
|
53
|
+
if (listStack.length === 0) out += '\n\n';
|
|
54
|
+
break;
|
|
55
|
+
case 'h1':
|
|
56
|
+
case 'h2':
|
|
57
|
+
case 'h3':
|
|
58
|
+
case 'h4':
|
|
59
|
+
case 'h5':
|
|
60
|
+
case 'h6':
|
|
61
|
+
out += isClosing ? '\n\n' : `\n\n${'#'.repeat(Number(tag[1]))} `;
|
|
62
|
+
break;
|
|
63
|
+
case 'strong':
|
|
64
|
+
case 'b':
|
|
65
|
+
out += '**';
|
|
66
|
+
break;
|
|
67
|
+
case 'em':
|
|
68
|
+
case 'i':
|
|
69
|
+
out += '_';
|
|
70
|
+
break;
|
|
71
|
+
case 'a':
|
|
72
|
+
if (!isClosing) {
|
|
73
|
+
const hrefMatch = attrs.match(/href=["']([^"']*)["']/i);
|
|
74
|
+
linkStack.push(hrefMatch ? hrefMatch[1] : '');
|
|
75
|
+
out += '[';
|
|
76
|
+
} else {
|
|
77
|
+
const href = linkStack.pop() ?? '';
|
|
78
|
+
out += `](${href})`;
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
case 'img': {
|
|
82
|
+
const srcMatch = attrs.match(/src=["']([^"']*)["']/i);
|
|
83
|
+
out += ``;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case 'ul':
|
|
87
|
+
case 'ol':
|
|
88
|
+
if (!isClosing) listStack.push({ type: tag, index: 0 });
|
|
89
|
+
else listStack.pop();
|
|
90
|
+
out += '\n';
|
|
91
|
+
break;
|
|
92
|
+
case 'li':
|
|
93
|
+
if (!isClosing) {
|
|
94
|
+
const ctx = listStack[listStack.length - 1];
|
|
95
|
+
if (ctx && ctx.type === 'ol') {
|
|
96
|
+
ctx.index += 1;
|
|
97
|
+
out += `\n${ctx.index}. `;
|
|
98
|
+
} else {
|
|
99
|
+
out += '\n- ';
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
// Unknown/unsupported tag (span, table, etc.): drop the tag,
|
|
105
|
+
// keep its text content via the surrounding appendText calls.
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
appendText(html.slice(lastIndex));
|
|
110
|
+
|
|
111
|
+
return decodeEntities(out)
|
|
112
|
+
.replace(/[ \t]+\n/g, '\n')
|
|
113
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
114
|
+
.trim();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export { htmlToMarkdown };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import fetch from 'node-fetch';
|
|
2
|
+
|
|
3
|
+
// Generic Odoo execute_kw call against Trident. Throws on transport or Odoo error.
|
|
4
|
+
async function tridentRpc(model, method, args, kwargs = {}) {
|
|
5
|
+
const url = `${process.env.TRIDENT_URL}/jsonrpc`;
|
|
6
|
+
const body = {
|
|
7
|
+
jsonrpc: '2.0',
|
|
8
|
+
method: 'call',
|
|
9
|
+
id: 1,
|
|
10
|
+
params: {
|
|
11
|
+
service: 'object',
|
|
12
|
+
method: 'execute_kw',
|
|
13
|
+
args: [
|
|
14
|
+
process.env.TRIDENT_DB,
|
|
15
|
+
parseInt(process.env.TRIDENT_UID, 10),
|
|
16
|
+
process.env.TRIDENT_TOKEN,
|
|
17
|
+
model,
|
|
18
|
+
method,
|
|
19
|
+
args,
|
|
20
|
+
kwargs,
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
const res = await fetch(url, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: { 'Content-Type': 'application/json' },
|
|
27
|
+
body: JSON.stringify(body),
|
|
28
|
+
});
|
|
29
|
+
const data = await res.json();
|
|
30
|
+
if (data.error) throw new Error(`Trident error: ${JSON.stringify(data.error)}`);
|
|
31
|
+
return data.result;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { tridentRpc };
|