@waron97/prbot 2.0.0 → 2.2.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 CHANGED
@@ -1,34 +1,35 @@
1
1
  {
2
- "name": "@waron97/prbot",
3
- "version": "2.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
8
- },
9
- "bin": {
10
- "prbot": "src/index.js"
11
- },
12
- "dependencies": {
13
- "@inquirer/search": "^2.0.1",
14
- "commander": "^14.0.2",
15
- "dotenv": "^17.2.3",
16
- "eslint-plugin-es5": "^1.5.0",
17
- "inquirer": "^13.4.2",
18
- "node-fetch": "^3.3.2",
19
- "omelette": "^0.4.17",
20
- "prettier": "^3.5.3"
21
- },
22
- "devDependencies": {
23
- "@eslint/js": "^9.21.0",
24
- "@types/node": "^25.0.10",
25
- "@typescript-eslint/parser": "^8.26.0",
26
- "eslint": "^9.21.0",
27
- "typescript": "^5.8.2",
28
- "typescript-eslint": "^8.26.0"
29
- },
30
- "keywords": [],
31
- "author": "",
32
- "license": "ISC",
33
- "type": "module"
2
+ "name": "@waron97/prbot",
3
+ "version": "2.2.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "bin": {
10
+ "prbot": "src/index.js"
11
+ },
12
+ "dependencies": {
13
+ "@inquirer/search": "^2.0.1",
14
+ "commander": "^14.0.2",
15
+ "dotenv": "^17.2.3",
16
+ "eslint-plugin-es5": "^1.5.0",
17
+ "inquirer": "^13.4.2",
18
+ "inquirer-search-list": "^1.2.6",
19
+ "node-fetch": "^3.3.2",
20
+ "omelette": "^0.4.17",
21
+ "prettier": "^3.5.3"
22
+ },
23
+ "devDependencies": {
24
+ "@eslint/js": "^9.21.0",
25
+ "@types/node": "^25.0.10",
26
+ "@typescript-eslint/parser": "^8.26.0",
27
+ "eslint": "^9.21.0",
28
+ "typescript": "^5.8.2",
29
+ "typescript-eslint": "^8.26.0"
30
+ },
31
+ "keywords": [],
32
+ "author": "",
33
+ "license": "ISC",
34
+ "type": "module"
34
35
  }
@@ -1,309 +1,288 @@
1
- import fs from "fs/promises";
2
- import { readFileSync } from "fs";
3
- import fetch from "node-fetch";
4
- import inquirer from "inquirer";
5
- import search from "@inquirer/search";
6
- import { resolveAddonsPath } from "../lib/addons.js";
7
- import { execGit } from "../lib/git.js";
1
+ import { readFileSync } from 'fs';
2
+ import fs from 'fs/promises';
3
+ import search from '@inquirer/search';
4
+ import inquirer from 'inquirer';
5
+ import fetch from 'node-fetch';
6
+ import { resolveAddonsPath } from '../lib/addons.js';
7
+ import { execGit } from '../lib/git.js';
8
8
  import {
9
- extractSections,
10
- findSectionEndLine,
11
- detectIndentation,
12
- buildRefString,
13
- findDuplicateLine,
14
- appendPrToLine,
15
- } from "./changelog.js";
9
+ appendPrToLine,
10
+ buildRefString,
11
+ detectIndentation,
12
+ extractSections,
13
+ findDuplicateLine,
14
+ findSectionEndLine,
15
+ } from './changelog.js';
16
16
 
17
17
  function devopsHeaders() {
18
- const token = Buffer.from(`:${process.env.DEVOPS_TOKEN}`).toString("base64");
19
- return {
20
- Authorization: `Basic ${token}`,
21
- "Content-Type": "application/json",
22
- };
18
+ const token = Buffer.from(`:${process.env.DEVOPS_TOKEN}`).toString('base64');
19
+ return {
20
+ Authorization: `Basic ${token}`,
21
+ 'Content-Type': 'application/json',
22
+ };
23
23
  }
24
24
 
25
25
  async function fetchTask(taskId) {
26
- const url = `${process.env.TRIDENT_URL}/jsonrpc`;
27
- const body = {
28
- jsonrpc: "2.0",
29
- method: "call",
30
- id: 1,
31
- params: {
32
- service: "object",
33
- method: "execute_kw",
34
- args: [
35
- process.env.TRIDENT_DB,
36
- parseInt(process.env.TRIDENT_UID, 10),
37
- process.env.TRIDENT_TOKEN,
38
- "project.task",
39
- "read",
40
- [[parseInt(taskId, 10)]],
41
- {
42
- fields: [
43
- "name",
44
- "x_subpackage_id",
45
- "x_workflow",
46
- "x_release_checklist",
47
- ],
26
+ const url = `${process.env.TRIDENT_URL}/jsonrpc`;
27
+ const body = {
28
+ jsonrpc: '2.0',
29
+ method: 'call',
30
+ id: 1,
31
+ params: {
32
+ service: 'object',
33
+ method: 'execute_kw',
34
+ args: [
35
+ process.env.TRIDENT_DB,
36
+ parseInt(process.env.TRIDENT_UID, 10),
37
+ process.env.TRIDENT_TOKEN,
38
+ 'project.task',
39
+ 'read',
40
+ [[parseInt(taskId, 10)]],
41
+ {
42
+ fields: [
43
+ 'name',
44
+ 'x_subpackage_id',
45
+ 'x_workflow',
46
+ 'x_cluster_id',
47
+ 'x_release_checklist',
48
+ ],
49
+ },
50
+ ],
48
51
  },
49
- ],
50
- },
51
- };
52
- const res = await fetch(url, {
53
- method: "POST",
54
- headers: { "Content-Type": "application/json" },
55
- body: JSON.stringify(body),
56
- });
57
- const data = await res.json();
58
- if (data.error)
59
- throw new Error(`Trident error: ${JSON.stringify(data.error)}`);
60
- if (!data.result || !data.result[0])
61
- throw new Error(`Task ${taskId} not found`);
62
- return data.result[0];
52
+ };
53
+ const res = await fetch(url, {
54
+ method: 'POST',
55
+ headers: { 'Content-Type': 'application/json' },
56
+ body: JSON.stringify(body),
57
+ });
58
+ const data = await res.json();
59
+ if (data.error) throw new Error(`Trident error: ${JSON.stringify(data.error)}`);
60
+ if (!data.result || !data.result[0]) throw new Error(`Task ${taskId} not found`);
61
+ return data.result[0];
63
62
  }
64
63
 
65
64
  function buildPrDescription(taskIds, jiras) {
66
- const lines = taskIds.map(
67
- (id) => `${process.env.TRIDENT_URL}/odoo/my-tasks/${id}`,
68
- );
69
- for (const jira of jiras ?? []) {
70
- lines.push(`https://sorgenia.atlassian.net/browse/${jira}`);
71
- }
72
- return lines.join("\n");
65
+ const lines = taskIds.map((id) => `${process.env.TRIDENT_URL}/odoo/my-tasks/${id}`);
66
+ for (const jira of jiras ?? []) {
67
+ lines.push(`https://sorgenia.atlassian.net/browse/${jira}`);
68
+ }
69
+ return lines.join('\n');
73
70
  }
74
71
 
75
72
  async function createDevopsPR(branch, title, description) {
76
- const { DEVOPS_ORG, DEVOPS_PROJECT, DEVOPS_REPO, AUTOPR_TARGET_BRANCH } =
77
- process.env;
78
- const apiUrl = `https://dev.azure.com/${DEVOPS_ORG}/${DEVOPS_PROJECT}/_apis/git/repositories/${DEVOPS_REPO}/pullrequests?api-version=7.0`;
79
- const res = await fetch(apiUrl, {
80
- method: "POST",
81
- headers: devopsHeaders(),
82
- body: JSON.stringify({
83
- title,
84
- description,
85
- isDraft: true,
86
- sourceRefName: `refs/heads/${branch}`,
87
- targetRefName: `refs/heads/${AUTOPR_TARGET_BRANCH}`,
88
- }),
89
- });
90
- const data = await res.json();
91
- if (!res.ok)
92
- throw new Error(`DevOps PR creation failed: ${JSON.stringify(data)}`);
93
- const prUrl = `https://dev.azure.com/${DEVOPS_ORG}/${DEVOPS_PROJECT}/_git/${DEVOPS_REPO}/pullrequest/${data.pullRequestId}`;
94
- return { id: data.pullRequestId, url: prUrl };
73
+ const { DEVOPS_ORG, DEVOPS_PROJECT, DEVOPS_REPO, AUTOPR_TARGET_BRANCH } = process.env;
74
+ const apiUrl = `https://dev.azure.com/${DEVOPS_ORG}/${DEVOPS_PROJECT}/_apis/git/repositories/${DEVOPS_REPO}/pullrequests?api-version=7.0`;
75
+ const res = await fetch(apiUrl, {
76
+ method: 'POST',
77
+ headers: devopsHeaders(),
78
+ body: JSON.stringify({
79
+ title,
80
+ description,
81
+ isDraft: true,
82
+ sourceRefName: `refs/heads/${branch}`,
83
+ targetRefName: `refs/heads/${AUTOPR_TARGET_BRANCH}`,
84
+ }),
85
+ });
86
+ const data = await res.json();
87
+ if (!res.ok) throw new Error(`DevOps PR creation failed: ${JSON.stringify(data)}`);
88
+ const prUrl = `https://dev.azure.com/${DEVOPS_ORG}/${DEVOPS_PROJECT}/_git/${DEVOPS_REPO}/pullrequest/${data.pullRequestId}`;
89
+ return { id: data.pullRequestId, url: prUrl };
95
90
  }
96
91
 
97
92
  async function appendChecklistPrLink(taskId, currentChecklist, prUrl, prNumber) {
98
- const link = `<a href="${prUrl}">${prUrl}</a><br/>`;
99
- const updated = currentChecklist ? `${currentChecklist}\n${link}` : link;
100
- const url = `${process.env.TRIDENT_URL}/jsonrpc`;
101
- const res = await fetch(url, {
102
- method: "POST",
103
- headers: { "Content-Type": "application/json" },
104
- body: JSON.stringify({
105
- jsonrpc: "2.0",
106
- method: "call",
107
- id: 2,
108
- params: {
109
- service: "object",
110
- method: "execute_kw",
111
- args: [
112
- process.env.TRIDENT_DB,
113
- parseInt(process.env.TRIDENT_UID, 10),
114
- process.env.TRIDENT_TOKEN,
115
- "project.task",
116
- "write",
117
- [[parseInt(taskId, 10)], { x_release_checklist: updated }],
118
- ],
119
- },
120
- }),
121
- });
122
- const data = await res.json();
123
- if (data.error)
124
- throw new Error(`Trident write error: ${JSON.stringify(data.error)}`);
93
+ const link = `<a href="${prUrl}">${prUrl}</a><br/>`;
94
+ const updated = currentChecklist ? `${currentChecklist}\n${link}` : link;
95
+ const url = `${process.env.TRIDENT_URL}/jsonrpc`;
96
+ const res = await fetch(url, {
97
+ method: 'POST',
98
+ headers: { 'Content-Type': 'application/json' },
99
+ body: JSON.stringify({
100
+ jsonrpc: '2.0',
101
+ method: 'call',
102
+ id: 2,
103
+ params: {
104
+ service: 'object',
105
+ method: 'execute_kw',
106
+ args: [
107
+ process.env.TRIDENT_DB,
108
+ parseInt(process.env.TRIDENT_UID, 10),
109
+ process.env.TRIDENT_TOKEN,
110
+ 'project.task',
111
+ 'write',
112
+ [[parseInt(taskId, 10)], { x_release_checklist: updated }],
113
+ ],
114
+ },
115
+ }),
116
+ });
117
+ const data = await res.json();
118
+ if (data.error) throw new Error(`Trident write error: ${JSON.stringify(data.error)}`);
125
119
  }
126
120
 
127
121
  function scoreSections(sections, candidates) {
128
- const results = [];
129
- for (const section of sections) {
130
- const heading = section.heading.replace(/^### /, "").toLowerCase().trim();
131
- let score = 0;
132
- for (const candidate of candidates) {
133
- const lc = candidate.toLowerCase().trim();
134
- if (heading === lc) {
135
- score += 100;
136
- continue;
137
- }
138
- if (heading.includes(lc) || lc.includes(heading)) {
139
- score += 50;
140
- continue;
141
- }
142
- // Match by first pipe-segment (e.g. "CROSS_31.1 - ML")
143
- const candidatePrefix = lc.split("|")[0].trim();
144
- const headingPrefix = heading.split("|")[0].trim();
145
- if (
146
- headingPrefix.includes(candidatePrefix) ||
147
- candidatePrefix.includes(headingPrefix)
148
- ) {
149
- score += 20;
150
- continue;
151
- }
152
- // Token fallback
153
- const tokens = lc
154
- .split(/[\s|_\-.]+/)
155
- .filter((t) => t.length > 2);
156
- for (const token of tokens) {
157
- if (heading.includes(token)) score++;
158
- }
122
+ const results = [];
123
+ for (const section of sections) {
124
+ const heading = section.heading.replace(/^### /, '').toLowerCase().trim();
125
+ let score = 0;
126
+ for (const candidate of candidates) {
127
+ const lc = candidate.toLowerCase().trim();
128
+ if (heading === lc) {
129
+ score += 100;
130
+ continue;
131
+ }
132
+ if (heading.includes(lc) || lc.includes(heading)) {
133
+ score += 50;
134
+ continue;
135
+ }
136
+ // Match by first pipe-segment (e.g. "CROSS_31.1 - ML")
137
+ const candidatePrefix = lc.split('|')[0].trim();
138
+ const headingPrefix = heading.split('|')[0].trim();
139
+ if (
140
+ headingPrefix.includes(candidatePrefix) ||
141
+ candidatePrefix.includes(headingPrefix)
142
+ ) {
143
+ score += 20;
144
+ continue;
145
+ }
146
+ // Token fallback
147
+ const tokens = lc.split(/[\s|_\-.]+/).filter((t) => t.length > 2);
148
+ for (const token of tokens) {
149
+ if (heading.includes(token)) score++;
150
+ }
151
+ }
152
+ if (score > 0) results.push({ ...section, score });
159
153
  }
160
- if (score > 0) results.push({ ...section, score });
161
- }
162
- return results.sort((a, b) => b.score - a.score).slice(0, 3);
154
+ return results.sort((a, b) => b.score - a.score).slice(0, 3);
163
155
  }
164
156
 
165
157
  async function selectSection(sections, candidates) {
166
- const scored = candidates.length > 0 ? scoreSections(sections, candidates) : [];
158
+ const scored = candidates.length > 0 ? scoreSections(sections, candidates) : [];
167
159
 
168
- if (candidates.length > 0) {
169
- console.log(`\nTask fields: ${candidates.join(" | ")}`);
170
- if (scored.length === 0) console.log("No matching sections found.");
171
- }
160
+ if (candidates.length > 0) {
161
+ console.log(`\nTask fields: ${candidates.join(' | ')}`);
162
+ if (scored.length === 0) console.log('No matching sections found.');
163
+ }
172
164
 
173
- const scoredHeadings = new Set(scored.map((s) => s.heading));
174
- const topChoices = scored.map((s) => ({
175
- name: `${s.heading.replace(/^### /, "")} ✓`,
176
- value: s.heading,
177
- }));
178
- const restChoices = sections
179
- .filter((s) => !scoredHeadings.has(s.heading))
180
- .map((s) => ({ name: s.heading.replace(/^### /, ""), value: s.heading }));
181
- const allChoices = [...topChoices, ...restChoices];
165
+ const scoredHeadings = new Set(scored.map((s) => s.heading));
166
+ const topChoices = scored.map((s) => ({
167
+ name: `${s.heading.replace(/^### /, '')} ✓`,
168
+ value: s.heading,
169
+ }));
170
+ const restChoices = sections
171
+ .filter((s) => !scoredHeadings.has(s.heading))
172
+ .map((s) => ({ name: s.heading.replace(/^### /, ''), value: s.heading }));
173
+ const allChoices = [...topChoices, ...restChoices];
182
174
 
183
- const selected = await search({
184
- message: "Select changelog section:",
185
- source: async (input) => {
186
- if (!input) return allChoices;
187
- return allChoices.filter((c) =>
188
- c.value.toLowerCase().includes(input.toLowerCase()),
189
- );
190
- },
191
- });
192
- return sections.find((s) => s.heading === selected);
175
+ const selected = await search({
176
+ message: 'Select changelog section:',
177
+ source: async (input) => {
178
+ if (!input) return allChoices;
179
+ return allChoices.filter((c) => c.value.toLowerCase().includes(input.toLowerCase()));
180
+ },
181
+ });
182
+ return sections.find((s) => s.heading === selected);
193
183
  }
194
184
 
195
185
  async function autopr(options) {
196
- const ADDONS_PATH = resolveAddonsPath(process.env.ADDONS_PATH);
197
- const changelogPath = `${ADDONS_PATH}/CHANGELOG.md`;
186
+ const ADDONS_PATH = resolveAddonsPath(process.env.ADDONS_PATH);
187
+ const changelogPath = `${ADDONS_PATH}/CHANGELOG.md`;
198
188
 
199
- const ids = options.trident ?? [];
200
- const hasTridents = ids.length > 0;
189
+ const ids = options.trident ?? [];
190
+ const hasTridents = ids.length > 0;
201
191
 
202
- const tasks = hasTridents
203
- ? await Promise.all(ids.map((id) => fetchTask(id)))
204
- : [];
205
- tasks.forEach((t) => console.log(`Task: ${t.name}`));
192
+ const tasks = hasTridents ? await Promise.all(ids.map((id) => fetchTask(id))) : [];
193
+ tasks.forEach((t) => console.log(`Task: ${t.name}`));
206
194
 
207
- const content = readFileSync(changelogPath, "utf-8");
195
+ const content = readFileSync(changelogPath, 'utf-8');
208
196
 
209
- const duplicate = hasTridents
210
- ? findDuplicateLine(content, ids, [])
211
- : null;
197
+ const duplicate = hasTridents ? findDuplicateLine(content, ids, []) : null;
212
198
 
213
- let appendMode = false;
214
- if (duplicate) {
215
- console.log(`\nExisting entry (line ${duplicate.lineNumber + 1}):\n ${duplicate.line}`);
216
- const { confirm } = await inquirer.prompt([
217
- {
218
- type: "confirm",
219
- name: "confirm",
220
- message: "Append PR ref to existing entry?",
221
- default: true,
222
- },
223
- ]);
224
- appendMode = confirm;
225
- }
199
+ let appendMode = false;
200
+ if (duplicate) {
201
+ console.log(`\nExisting entry (line ${duplicate.lineNumber + 1}):\n ${duplicate.line}`);
202
+ const { confirm } = await inquirer.prompt([
203
+ {
204
+ type: 'confirm',
205
+ name: 'confirm',
206
+ message: 'Append PR ref to existing entry?',
207
+ default: true,
208
+ },
209
+ ]);
210
+ appendMode = confirm;
211
+ }
226
212
 
227
- const branch =
228
- options.branch ??
229
- (ids[0]
230
- ? `autopr_${ids[0]}`
231
- : options.jira?.[0]
232
- ? `autopr_${options.jira[0]}`
233
- : null);
234
- if (!branch)
235
- throw new Error(
236
- "No branch name: provide --branch, a task ID, or --jira",
237
- );
213
+ const branch =
214
+ options.branch ??
215
+ (ids[0] ? `autopr_${ids[0]}` : options.jira?.[0] ? `autopr_${options.jira[0]}` : null);
216
+ if (!branch) throw new Error('No branch name: provide --branch, a task ID, or --jira');
238
217
 
239
- let message = null;
240
- if (!appendMode) {
241
- message = options.message;
242
- if (!message) {
243
- const answer = await inquirer.prompt([
244
- { type: "input", name: "message", message: "Changelog entry message:" },
245
- ]);
246
- message = answer.message;
218
+ let message = null;
219
+ if (!appendMode) {
220
+ message = options.message;
221
+ if (!message) {
222
+ const answer = await inquirer.prompt([
223
+ { type: 'input', name: 'message', message: 'Changelog entry message:' },
224
+ ]);
225
+ message = answer.message;
226
+ }
247
227
  }
248
- }
249
228
 
250
- await execGit(["checkout", "-b", branch], ADDONS_PATH);
251
- console.log(`Branch created: ${branch}`);
252
- await execGit(["push", "-u", "origin", branch], ADDONS_PATH);
229
+ await execGit(['checkout', '-b', branch], ADDONS_PATH);
230
+ console.log(`Branch created: ${branch}`);
231
+ await execGit(['push', '-u', 'origin', branch], ADDONS_PATH);
253
232
 
254
- const prTitle = options.name ?? (tasks[0]?.name ?? branch);
255
- const prDescription = buildPrDescription(ids, options.jira ?? []);
256
- const { id: prNumber, url: prUrl } = await createDevopsPR(branch, prTitle, prDescription);
257
- console.log(`PR opened: #${prNumber} — ${prUrl}`);
233
+ const prTitle = options.name ?? tasks[0]?.name ?? branch;
234
+ const prDescription = buildPrDescription(ids, options.jira ?? []);
235
+ const { id: prNumber, url: prUrl } = await createDevopsPR(branch, prTitle, prDescription);
236
+ console.log(`PR opened: #${prNumber} — ${prUrl}`);
258
237
 
259
- if (hasTridents) {
260
- for (let i = 0; i < ids.length; i++) {
261
- await appendChecklistPrLink(ids[i], tasks[i].x_release_checklist, prUrl, prNumber);
238
+ if (hasTridents) {
239
+ for (let i = 0; i < ids.length; i++) {
240
+ await appendChecklistPrLink(ids[i], tasks[i].x_release_checklist, prUrl, prNumber);
241
+ }
242
+ console.log('Checklist updated');
262
243
  }
263
- console.log("Checklist updated");
264
- }
265
244
 
266
- const lines = content.split("\n");
245
+ const lines = content.split('\n');
267
246
 
268
- if (appendMode) {
269
- lines[duplicate.lineNumber] = appendPrToLine(lines[duplicate.lineNumber], prNumber);
270
- } else {
271
- const sections = extractSections(content);
272
- const candidates = [];
273
- if (hasTridents) {
274
- const anchor = tasks.find(
275
- (t) =>
276
- (Array.isArray(t.x_subpackage_id) && t.x_subpackage_id[1]) ||
277
- (Array.isArray(t.x_workflow) && t.x_workflow[1]),
278
- );
279
- if (anchor) {
280
- if (Array.isArray(anchor.x_subpackage_id) && anchor.x_subpackage_id[1])
281
- candidates.push(anchor.x_subpackage_id[1]);
282
- if (Array.isArray(anchor.x_workflow) && anchor.x_workflow[1])
283
- candidates.push(anchor.x_workflow[1]);
284
- }
285
- }
247
+ if (appendMode) {
248
+ lines[duplicate.lineNumber] = appendPrToLine(lines[duplicate.lineNumber], prNumber);
249
+ } else {
250
+ const sections = extractSections(content);
251
+ const candidates = [];
252
+ if (hasTridents) {
253
+ const anchor = tasks.find(
254
+ (t) =>
255
+ (Array.isArray(t.x_subpackage_id) && t.x_subpackage_id[1]) ||
256
+ (Array.isArray(t.x_workflow) && t.x_workflow[1]) ||
257
+ (Array.isArray(t.x_cluster_id) && t.x_cluster_id[1])
258
+ );
259
+ if (anchor) {
260
+ if (Array.isArray(anchor.x_subpackage_id) && anchor.x_subpackage_id[1])
261
+ candidates.push(anchor.x_subpackage_id[1]);
262
+ if (Array.isArray(anchor.x_workflow) && anchor.x_workflow[1])
263
+ candidates.push(anchor.x_workflow[1]);
264
+ if (Array.isArray(anchor.x_cluster_id) && anchor.x_cluster_id[1])
265
+ candidates.push(anchor.x_cluster_id[1]);
266
+ }
267
+ }
286
268
 
287
- const selectedSection = await selectSection(sections, candidates);
288
- const endLine = findSectionEndLine(lines, selectedSection.startLine);
289
- const indent = detectIndentation(lines, selectedSection.startLine, endLine);
269
+ const selectedSection = await selectSection(sections, candidates);
270
+ const endLine = findSectionEndLine(lines, selectedSection.startLine);
271
+ const indent = detectIndentation(lines, selectedSection.startLine, endLine);
290
272
 
291
- const jiras = options.jira ?? [];
292
- const refString = buildRefString(ids, jiras, prNumber);
293
- const newEntry = `${indent}- ${message}${refString ? " " + refString : ""}`;
294
- lines.splice(endLine + 1, 0, newEntry);
295
- }
273
+ const jiras = options.jira ?? [];
274
+ const refString = buildRefString(ids, jiras, prNumber);
275
+ const newEntry = `${indent}- ${message}${refString ? ' ' + refString : ''}`;
276
+ lines.splice(endLine + 1, 0, newEntry);
277
+ }
296
278
 
297
- await fs.writeFile(changelogPath, lines.join("\n"));
298
- console.log("Changelog entry written");
279
+ await fs.writeFile(changelogPath, lines.join('\n'));
280
+ console.log('Changelog entry written');
299
281
 
300
- await execGit(["add", "CHANGELOG.md"], ADDONS_PATH);
301
- await execGit(
302
- ["commit", "-m", "[DOC][CHANGELOG] Changelog"],
303
- ADDONS_PATH,
304
- );
305
- await execGit(["push"], ADDONS_PATH);
306
- console.log("Changelog committed and pushed");
282
+ await execGit(['add', 'CHANGELOG.md'], ADDONS_PATH);
283
+ await execGit(['commit', '-m', '[DOC][CHANGELOG] Changelog'], ADDONS_PATH);
284
+ await execGit(['push'], ADDONS_PATH);
285
+ console.log('Changelog committed and pushed');
307
286
  }
308
287
 
309
288
  export { autopr };