renovate 43.226.2 → 43.227.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.
@@ -1,6 +1,6 @@
1
1
  import { logger } from "../../../logger/index.js";
2
2
  import { ExternalHostError } from "../../../types/errors/external-host-error.js";
3
- import { PRESET_DEP_NOT_FOUND, fetchPreset, parsePreset } from "../util.js";
3
+ import { PRESET_DEP_NOT_FOUND, PRESET_INVALID, fetchPreset, parsePreset } from "../util.js";
4
4
  import { getRepoContents } from "../../../modules/platform/forgejo/forgejo-helper.js";
5
5
  //#region lib/config/presets/forgejo/index.ts
6
6
  const Endpoint = "https://code.forgejo.org/";
@@ -13,7 +13,13 @@ async function fetchJSONFile(repo, fileName, endpoint, tag) {
13
13
  logger.debug(`Preset file ${fileName} not found in ${repo}: ${err.message}`);
14
14
  throw new Error(PRESET_DEP_NOT_FOUND);
15
15
  }
16
- return parsePreset(res.contentString, fileName);
16
+ let contentString;
17
+ if (res.type === "file") contentString = res.contentString;
18
+ else {
19
+ logger.debug(`Preset ${fileName} has unexpected type '${res.type}'. Only \`file\` is supported`);
20
+ throw new Error(PRESET_INVALID);
21
+ }
22
+ return parsePreset(contentString, fileName);
17
23
  }
18
24
  function getPresetFromEndpoint(repo, filePreset, presetPath, endpoint = Endpoint, tag) {
19
25
  return fetchPreset({
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../lib/config/presets/forgejo/index.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport { getRepoContents } from '../../../modules/platform/forgejo/forgejo-helper.ts';\nimport type { RepoContents } from '../../../modules/platform/forgejo/types.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport type { Nullish } from '../../../types/index.ts';\nimport type { Preset, PresetConfig } from '../types.ts';\nimport { PRESET_DEP_NOT_FOUND, fetchPreset, parsePreset } from '../util.ts';\n\nexport const Endpoint = 'https://code.forgejo.org/';\n\nexport async function fetchJSONFile(\n repo: string,\n fileName: string,\n endpoint: string,\n tag?: string | null,\n): Promise<Nullish<Preset>> {\n let res: RepoContents;\n try {\n res = await getRepoContents(repo, fileName, tag, {\n baseUrl: endpoint,\n });\n } catch (err) {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n logger.debug(\n `Preset file ${fileName} not found in ${repo}: ${err.message}`,\n );\n throw new Error(PRESET_DEP_NOT_FOUND);\n }\n\n return parsePreset(res.contentString, fileName);\n}\n\nexport function getPresetFromEndpoint(\n repo: string,\n filePreset: string,\n presetPath?: string,\n endpoint = Endpoint,\n tag?: string,\n): Promise<Nullish<Preset>> {\n return fetchPreset({\n repo,\n filePreset,\n presetPath,\n endpoint,\n tag,\n fetch: fetchJSONFile,\n });\n}\n\nexport function getPreset({\n repo,\n presetName = 'default',\n presetPath,\n tag = undefined,\n}: PresetConfig): Promise<Nullish<Preset>> {\n return getPresetFromEndpoint(repo, presetName, presetPath, Endpoint, tag);\n}\n"],"mappings":";;;;;AAQA,MAAa,WAAW;AAExB,eAAsB,cACpB,MACA,UACA,UACA,KAC0B;CAC1B,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,gBAAgB,MAAM,UAAU,KAAK,EAC/C,SAAS,SACX,CAAC;CACH,SAAS,KAAK;EACZ,IAAI,eAAe,mBACjB,MAAM;EAER,OAAO,MACL,eAAe,SAAS,gBAAgB,KAAK,IAAI,IAAI,SACvD;EACA,MAAM,IAAI,MAAM,oBAAoB;CACtC;CAEA,OAAO,YAAY,IAAI,eAAe,QAAQ;AAChD;AAEA,SAAgB,sBACd,MACA,YACA,YACA,WAAW,UACX,KAC0B;CAC1B,OAAO,YAAY;EACjB;EACA;EACA;EACA;EACA;EACA,OAAO;CACT,CAAC;AACH;AAEA,SAAgB,UAAU,EACxB,MACA,aAAa,WACb,YACA,MAAM,KAAA,KACmC;CACzC,OAAO,sBAAsB,MAAM,YAAY,YAAY,UAAU,GAAG;AAC1E"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../lib/config/presets/forgejo/index.ts"],"sourcesContent":["import { logger } from '../../../logger/index.ts';\nimport { getRepoContents } from '../../../modules/platform/forgejo/forgejo-helper.ts';\nimport type { RepoContents } from '../../../modules/platform/forgejo/schema.ts';\nimport { ExternalHostError } from '../../../types/errors/external-host-error.ts';\nimport type { Nullish } from '../../../types/index.ts';\nimport type { Preset, PresetConfig } from '../types.ts';\nimport {\n PRESET_DEP_NOT_FOUND,\n PRESET_INVALID,\n fetchPreset,\n parsePreset,\n} from '../util.ts';\n\nexport const Endpoint = 'https://code.forgejo.org/';\n\nexport async function fetchJSONFile(\n repo: string,\n fileName: string,\n endpoint: string,\n tag?: string | null,\n): Promise<Nullish<Preset>> {\n let res: RepoContents;\n try {\n res = await getRepoContents(repo, fileName, tag, {\n baseUrl: endpoint,\n });\n } catch (err) {\n if (err instanceof ExternalHostError) {\n throw err;\n }\n logger.debug(\n `Preset file ${fileName} not found in ${repo}: ${err.message}`,\n );\n throw new Error(PRESET_DEP_NOT_FOUND);\n }\n\n let contentString: string;\n if (res.type === 'file') {\n contentString = res.contentString;\n } else {\n logger.debug(\n `Preset ${fileName} has unexpected type '${res.type}'. Only \\`file\\` is supported`,\n );\n throw new Error(PRESET_INVALID);\n }\n return parsePreset(contentString, fileName);\n}\n\nexport function getPresetFromEndpoint(\n repo: string,\n filePreset: string,\n presetPath?: string,\n endpoint = Endpoint,\n tag?: string,\n): Promise<Nullish<Preset>> {\n return fetchPreset({\n repo,\n filePreset,\n presetPath,\n endpoint,\n tag,\n fetch: fetchJSONFile,\n });\n}\n\nexport function getPreset({\n repo,\n presetName = 'default',\n presetPath,\n tag = undefined,\n}: PresetConfig): Promise<Nullish<Preset>> {\n return getPresetFromEndpoint(repo, presetName, presetPath, Endpoint, tag);\n}\n"],"mappings":";;;;;AAaA,MAAa,WAAW;AAExB,eAAsB,cACpB,MACA,UACA,UACA,KAC0B;CAC1B,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,gBAAgB,MAAM,UAAU,KAAK,EAC/C,SAAS,SACX,CAAC;CACH,SAAS,KAAK;EACZ,IAAI,eAAe,mBACjB,MAAM;EAER,OAAO,MACL,eAAe,SAAS,gBAAgB,KAAK,IAAI,IAAI,SACvD;EACA,MAAM,IAAI,MAAM,oBAAoB;CACtC;CAEA,IAAI;CACJ,IAAI,IAAI,SAAS,QACf,gBAAgB,IAAI;MACf;EACL,OAAO,MACL,UAAU,SAAS,wBAAwB,IAAI,KAAK,8BACtD;EACA,MAAM,IAAI,MAAM,cAAc;CAChC;CACA,OAAO,YAAY,eAAe,QAAQ;AAC5C;AAEA,SAAgB,sBACd,MACA,YACA,YACA,WAAW,UACX,KAC0B;CAC1B,OAAO,YAAY;EACjB;EACA;EACA;EACA;EACA;EACA,OAAO;CACT,CAAC;AACH;AAEA,SAAgB,UAAU,EACxB,MACA,aAAa,WACb,YACA,MAAM,KAAA,KACmC;CACzC,OAAO,sBAAsB,MAAM,YAAY,YAAY,UAAU,GAAG;AAC1E"}
@@ -1,10 +1,11 @@
1
- import { fromBase64 } from "../../../util/string.js";
2
1
  import { logger } from "../../../logger/index.js";
3
2
  import { getQueryString } from "../../../util/url.js";
4
3
  import { getCache } from "../../../util/cache/repository/index.js";
5
4
  import { ForgejoHttp } from "../../../util/http/forgejo.js";
5
+ import { Comment, CommitStatus, Issue, Label, PR, Repo, RepoContents, RepoSearchResults, User, Version } from "./schema.js";
6
6
  import { API_PATH } from "./utils.js";
7
7
  import { isBoolean } from "@sindresorhus/is";
8
+ import { z } from "zod/v4";
8
9
  //#region lib/modules/platform/forgejo/forgejo-helper.ts
9
10
  const forgejoHttp = new ForgejoHttp();
10
11
  const urlEscape = (raw) => encodeURIComponent(raw);
@@ -16,13 +17,13 @@ const commitStatusStates = [
16
17
  "failure",
17
18
  "error"
18
19
  ];
19
- async function getCurrentUser(options) {
20
+ async function getCurrentUser(options = {}) {
20
21
  const url = `${API_PATH}/user`;
21
- return (await forgejoHttp.getJsonUnchecked(url, options)).body;
22
+ return (await forgejoHttp.getJson(url, options, User)).body;
22
23
  }
23
- async function getVersion(options) {
24
+ async function getVersion(options = {}) {
24
25
  const url = `${API_PATH}/version`;
25
- return (await forgejoHttp.getJsonUnchecked(url, options)).body.version;
26
+ return (await forgejoHttp.getJson(url, options, Version)).body.version;
26
27
  }
27
28
  async function isOrg(organization) {
28
29
  const repoCache = getCache();
@@ -43,44 +44,42 @@ async function isOrg(organization) {
43
44
  }
44
45
  async function searchRepos(params, options) {
45
46
  const url = `${API_PATH}/repos/search?${getQueryString(params)}`;
46
- const res = await forgejoHttp.getJsonUnchecked(url, {
47
+ const res = await forgejoHttp.getJson(url, {
47
48
  ...options,
48
49
  paginate: true
49
- });
50
+ }, RepoSearchResults);
50
51
  if (!res.body.ok) throw new Error("Unable to search for repositories, ok flag has not been set");
51
52
  return res.body.data;
52
53
  }
53
54
  async function orgListRepos(organization, options) {
54
55
  const url = `${API_PATH}/orgs/${organization}/repos`;
55
- return (await forgejoHttp.getJsonUnchecked(url, {
56
+ return (await forgejoHttp.getJson(url, {
56
57
  ...options,
57
58
  paginate: true
58
- })).body;
59
+ }, z.array(Repo))).body;
59
60
  }
60
- async function getRepo(repoPath, options) {
61
+ async function getRepo(repoPath, options = {}) {
61
62
  const url = `${API_PATH}/repos/${repoPath}`;
62
- return (await forgejoHttp.getJsonUnchecked(url, options)).body;
63
+ return (await forgejoHttp.getJson(url, options, Repo)).body;
63
64
  }
64
- async function getRepoContents(repoPath, filePath, ref, options) {
65
+ async function getRepoContents(repoPath, filePath, ref, options = {}) {
65
66
  const query = getQueryString(ref ? { ref } : {});
66
67
  const url = `${API_PATH}/repos/${repoPath}/contents/${urlEscape(filePath)}?${query}`;
67
- const res = await forgejoHttp.getJsonUnchecked(url, options);
68
- if (res.body.content) res.body.contentString = fromBase64(res.body.content);
69
- return res.body;
68
+ return (await forgejoHttp.getJson(url, options, RepoContents)).body;
70
69
  }
71
70
  async function createPR(repoPath, params, options) {
72
71
  const url = `${API_PATH}/repos/${repoPath}/pulls`;
73
72
  return (await forgejoHttp.postJson(url, {
74
73
  ...options,
75
74
  body: params
76
- })).body;
75
+ }, PR)).body;
77
76
  }
78
77
  async function updatePR(repoPath, idx, params, options) {
79
78
  const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}`;
80
79
  return (await forgejoHttp.patchJson(url, {
81
80
  ...options,
82
81
  body: params
83
- })).body;
82
+ }, PR)).body;
84
83
  }
85
84
  async function mergePR(repoPath, idx, params, options) {
86
85
  const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}/merge`;
@@ -89,14 +88,14 @@ async function mergePR(repoPath, idx, params, options) {
89
88
  body: params
90
89
  });
91
90
  }
92
- async function getPR(repoPath, idx, options) {
91
+ async function getPR(repoPath, idx, options = {}) {
93
92
  const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}`;
94
- return (await forgejoHttp.getJsonUnchecked(url, options)).body;
93
+ return (await forgejoHttp.getJson(url, options, PR)).body;
95
94
  }
96
- async function getPRByBranch(repoPath, base, head, options) {
95
+ async function getPRByBranch(repoPath, base, head, options = {}) {
97
96
  const url = `${API_PATH}/repos/${repoPath}/pulls/${base}/${head}`;
98
97
  try {
99
- return (await forgejoHttp.getJsonUnchecked(url, options)).body;
98
+ return (await forgejoHttp.getJson(url, options, PR)).body;
100
99
  } catch (err) {
101
100
  logger.trace({ err }, "Error while fetching PR");
102
101
  if (err.statusCode !== 404) logger.debug({ err }, "Error while fetching PR");
@@ -115,21 +114,21 @@ async function createIssue(repoPath, params, options) {
115
114
  return (await forgejoHttp.postJson(url, {
116
115
  ...options,
117
116
  body: params
118
- })).body;
117
+ }, Issue)).body;
119
118
  }
120
119
  async function updateIssue(repoPath, idx, params, options) {
121
120
  const url = `${API_PATH}/repos/${repoPath}/issues/${idx}`;
122
121
  return (await forgejoHttp.patchJson(url, {
123
122
  ...options,
124
123
  body: params
125
- })).body;
124
+ }, Issue)).body;
126
125
  }
127
126
  async function updateIssueLabels(repoPath, idx, params, options) {
128
127
  const url = `${API_PATH}/repos/${repoPath}/issues/${idx}/labels`;
129
128
  return (await forgejoHttp.putJson(url, {
130
129
  ...options,
131
130
  body: params
132
- })).body;
131
+ }, z.array(Label))).body;
133
132
  }
134
133
  async function closeIssue(repoPath, idx, options) {
135
134
  await updateIssue(repoPath, idx, {
@@ -142,22 +141,22 @@ async function searchIssues(repoPath, params, options) {
142
141
  ...params,
143
142
  type: "issues"
144
143
  })}`;
145
- return (await forgejoHttp.getJsonUnchecked(url, {
144
+ return (await forgejoHttp.getJson(url, {
146
145
  ...options,
147
146
  paginate: true
148
- })).body;
147
+ }, z.array(Issue))).body;
149
148
  }
150
- async function getIssue(repoPath, idx, options) {
149
+ async function getIssue(repoPath, idx, options = {}) {
151
150
  const url = `${API_PATH}/repos/${repoPath}/issues/${idx}`;
152
- return (await forgejoHttp.getJsonUnchecked(url, options)).body;
151
+ return (await forgejoHttp.getJson(url, options, Issue)).body;
153
152
  }
154
- async function getRepoLabels(repoPath, options) {
153
+ async function getRepoLabels(repoPath, options = {}) {
155
154
  const url = `${API_PATH}/repos/${repoPath}/labels`;
156
- return (await forgejoHttp.getJsonUnchecked(url, options)).body;
155
+ return (await forgejoHttp.getJson(url, options, z.array(Label))).body;
157
156
  }
158
- async function getOrgLabels(orgName, options) {
157
+ async function getOrgLabels(orgName, options = {}) {
159
158
  const url = `${API_PATH}/orgs/${orgName}/labels`;
160
- return (await forgejoHttp.getJsonUnchecked(url, options)).body;
159
+ return (await forgejoHttp.getJson(url, options, z.array(Label))).body;
161
160
  }
162
161
  async function unassignLabel(repoPath, issue, label, options) {
163
162
  const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/labels/${label}`;
@@ -169,7 +168,7 @@ async function createComment(repoPath, issue, body, options) {
169
168
  return (await forgejoHttp.postJson(url, {
170
169
  ...options,
171
170
  body: params
172
- })).body;
171
+ }, Comment)).body;
173
172
  }
174
173
  async function updateComment(repoPath, idx, body, options) {
175
174
  const params = { body };
@@ -177,22 +176,22 @@ async function updateComment(repoPath, idx, body, options) {
177
176
  return (await forgejoHttp.patchJson(url, {
178
177
  ...options,
179
178
  body: params
180
- })).body;
179
+ }, Comment)).body;
181
180
  }
182
181
  async function deleteComment(repoPath, idx, options) {
183
182
  const url = `${API_PATH}/repos/${repoPath}/issues/comments/${idx}`;
184
183
  await forgejoHttp.deleteJson(url, options);
185
184
  }
186
- async function getComments(repoPath, issue, options) {
185
+ async function getComments(repoPath, issue, options = {}) {
187
186
  const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/comments`;
188
- return (await forgejoHttp.getJsonUnchecked(url, options)).body;
187
+ return (await forgejoHttp.getJson(url, options, z.array(Comment))).body;
189
188
  }
190
189
  async function createCommitStatus(repoPath, branchCommit, params, options) {
191
190
  const url = `${API_PATH}/repos/${repoPath}/statuses/${branchCommit}`;
192
191
  return (await forgejoHttp.postJson(url, {
193
192
  ...options,
194
193
  body: params
195
- })).body;
194
+ }, CommitStatus)).body;
196
195
  }
197
196
  const forgejoToRenovateStatusMapping = {
198
197
  unknown: "yellow",
@@ -214,10 +213,10 @@ function filterStatus(data) {
214
213
  }
215
214
  async function getCombinedCommitStatus(repoPath, branchName, options) {
216
215
  const url = `${API_PATH}/repos/${repoPath}/commits/${urlEscape(branchName)}/statuses`;
217
- const res = await forgejoHttp.getJsonUnchecked(url, {
216
+ const res = await forgejoHttp.getJson(url, {
218
217
  ...options,
219
218
  paginate: true
220
- });
219
+ }, z.array(CommitStatus));
221
220
  let worstState = 0;
222
221
  const statuses = filterStatus(res.body);
223
222
  for (const cs of statuses) worstState = Math.max(worstState, commitStatusStates.indexOf(cs.status));
@@ -1 +1 @@
1
- {"version":3,"file":"forgejo-helper.js","names":[],"sources":["../../../../lib/modules/platform/forgejo/forgejo-helper.ts"],"sourcesContent":["import { isBoolean } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport type { BranchStatus } from '../../../types/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { ForgejoHttpOptions } from '../../../util/http/forgejo.ts';\nimport { ForgejoHttp } from '../../../util/http/forgejo.ts';\nimport { fromBase64 } from '../../../util/string.ts';\nimport { getQueryString } from '../../../util/url.ts';\nimport type {\n Branch,\n CombinedCommitStatus,\n Comment,\n CommentCreateParams,\n CommentUpdateParams,\n CommitStatus,\n CommitStatusCreateParams,\n CommitStatusType,\n Issue,\n IssueCreateParams,\n IssueSearchParams,\n IssueUpdateLabelsParams,\n IssueUpdateParams,\n Label,\n PR,\n PRCreateParams,\n PRMergeParams,\n PRUpdateParams,\n PrReviewersParams,\n Repo,\n RepoContents,\n RepoSearchParams,\n RepoSearchResults,\n User,\n} from './types.ts';\nimport { API_PATH } from './utils.ts';\n\nexport const forgejoHttp = new ForgejoHttp();\n\nconst urlEscape = (raw: string): string => encodeURIComponent(raw);\nconst commitStatusStates: CommitStatusType[] = [\n 'unknown',\n 'success',\n 'pending',\n 'warning',\n 'failure',\n 'error',\n];\n\nexport async function getCurrentUser(\n options?: ForgejoHttpOptions,\n): Promise<User> {\n const url = `${API_PATH}/user`;\n const res = await forgejoHttp.getJsonUnchecked<User>(url, options);\n return res.body;\n}\n\nexport async function getVersion(\n options?: ForgejoHttpOptions,\n): Promise<string> {\n const url = `${API_PATH}/version`;\n const res = await forgejoHttp.getJsonUnchecked<{ version: string }>(\n url,\n options,\n );\n return res.body.version;\n}\n\nexport async function isOrg(organization: string): Promise<boolean> {\n const repoCache = getCache();\n repoCache.platform ??= {};\n repoCache.platform.forgejo ??= {};\n repoCache.platform.forgejo.orgs ??= {};\n const cached = repoCache.platform.forgejo.orgs[organization];\n if (isBoolean(cached)) {\n return cached;\n }\n try {\n const url = `${API_PATH}/orgs/${organization}`;\n const res = await forgejoHttp.getJsonUnchecked(url);\n repoCache.platform.forgejo.orgs[organization] = res.statusCode === 200;\n return res.statusCode === 200;\n } catch (err) {\n if (err.statusCode === 404) {\n return false;\n }\n // throw other errors\n throw err;\n }\n}\n\nexport async function searchRepos(\n params: RepoSearchParams,\n options?: ForgejoHttpOptions,\n): Promise<Repo[]> {\n const query = getQueryString(params);\n const url = `${API_PATH}/repos/search?${query}`;\n const res = await forgejoHttp.getJsonUnchecked<RepoSearchResults>(url, {\n ...options,\n paginate: true,\n });\n\n if (!res.body.ok) {\n throw new Error(\n 'Unable to search for repositories, ok flag has not been set',\n );\n }\n\n return res.body.data;\n}\n\nexport async function orgListRepos(\n organization: string,\n options?: ForgejoHttpOptions,\n): Promise<Repo[]> {\n const url = `${API_PATH}/orgs/${organization}/repos`;\n const res = await forgejoHttp.getJsonUnchecked<Repo[]>(url, {\n ...options,\n paginate: true,\n });\n\n return res.body;\n}\n\nexport async function getRepo(\n repoPath: string,\n options?: ForgejoHttpOptions,\n): Promise<Repo> {\n const url = `${API_PATH}/repos/${repoPath}`;\n const res = await forgejoHttp.getJsonUnchecked<Repo>(url, options);\n return res.body;\n}\n\nexport async function getRepoContents(\n repoPath: string,\n filePath: string,\n ref?: string | null,\n options?: ForgejoHttpOptions,\n): Promise<RepoContents> {\n const query = getQueryString(ref ? { ref } : {});\n const url = `${API_PATH}/repos/${repoPath}/contents/${urlEscape(\n filePath,\n )}?${query}`;\n const res = await forgejoHttp.getJsonUnchecked<RepoContents>(url, options);\n\n if (res.body.content) {\n res.body.contentString = fromBase64(res.body.content);\n }\n\n return res.body;\n}\n\nexport async function createPR(\n repoPath: string,\n params: PRCreateParams,\n options?: ForgejoHttpOptions,\n): Promise<PR> {\n const url = `${API_PATH}/repos/${repoPath}/pulls`;\n const res = await forgejoHttp.postJson<PR>(url, {\n ...options,\n body: params,\n });\n\n return res.body;\n}\n\nexport async function updatePR(\n repoPath: string,\n idx: number,\n params: PRUpdateParams,\n options?: ForgejoHttpOptions,\n): Promise<PR> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}`;\n const res = await forgejoHttp.patchJson<PR>(url, {\n ...options,\n body: params,\n });\n\n return res.body;\n}\n\nexport async function closePR(\n repoPath: string,\n idx: number,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n await updatePR(repoPath, idx, {\n ...options,\n state: 'closed',\n });\n}\n\nexport async function mergePR(\n repoPath: string,\n idx: number,\n params: PRMergeParams,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}/merge`;\n await forgejoHttp.postJson(url, {\n ...options,\n body: params,\n });\n}\n\nexport async function getPR(\n repoPath: string,\n idx: number,\n options?: ForgejoHttpOptions,\n): Promise<PR> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}`;\n const res = await forgejoHttp.getJsonUnchecked<PR>(url, options);\n return res.body;\n}\n\nexport async function getPRByBranch(\n repoPath: string,\n base: string,\n head: string,\n options?: ForgejoHttpOptions,\n): Promise<PR | null> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${base}/${head}`;\n try {\n const res = await forgejoHttp.getJsonUnchecked<PR>(url, options);\n return res.body;\n } catch (err) {\n logger.trace({ err }, 'Error while fetching PR');\n if (err.statusCode !== 404) {\n logger.debug({ err }, 'Error while fetching PR');\n }\n return null;\n }\n}\n\nexport async function requestPrReviewers(\n repoPath: string,\n idx: number,\n params: PrReviewersParams,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}/requested_reviewers`;\n await forgejoHttp.postJson(url, {\n ...options,\n body: params,\n });\n}\n\nexport async function createIssue(\n repoPath: string,\n params: IssueCreateParams,\n options?: ForgejoHttpOptions,\n): Promise<Issue> {\n const url = `${API_PATH}/repos/${repoPath}/issues`;\n const res = await forgejoHttp.postJson<Issue>(url, {\n ...options,\n body: params,\n });\n\n return res.body;\n}\n\nexport async function updateIssue(\n repoPath: string,\n idx: number,\n params: IssueUpdateParams,\n options?: ForgejoHttpOptions,\n): Promise<Issue> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${idx}`;\n const res = await forgejoHttp.patchJson<Issue>(url, {\n ...options,\n body: params,\n });\n\n return res.body;\n}\n\nexport async function updateIssueLabels(\n repoPath: string,\n idx: number,\n params: IssueUpdateLabelsParams,\n options?: ForgejoHttpOptions,\n): Promise<Label[]> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${idx}/labels`;\n const res = await forgejoHttp.putJson<Label[]>(url, {\n ...options,\n body: params,\n });\n\n return res.body;\n}\n\nexport async function closeIssue(\n repoPath: string,\n idx: number,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n await updateIssue(repoPath, idx, {\n ...options,\n state: 'closed',\n });\n}\n\nexport async function searchIssues(\n repoPath: string,\n params: IssueSearchParams,\n options?: ForgejoHttpOptions,\n): Promise<Issue[]> {\n const query = getQueryString({ ...params, type: 'issues' });\n const url = `${API_PATH}/repos/${repoPath}/issues?${query}`;\n const res = await forgejoHttp.getJsonUnchecked<Issue[]>(url, {\n ...options,\n paginate: true,\n });\n\n return res.body;\n}\n\nexport async function getIssue(\n repoPath: string,\n idx: number,\n options?: ForgejoHttpOptions,\n): Promise<Issue> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${idx}`;\n const res = await forgejoHttp.getJsonUnchecked<Issue>(url, options);\n return res.body;\n}\n\nexport async function getRepoLabels(\n repoPath: string,\n options?: ForgejoHttpOptions,\n): Promise<Label[]> {\n const url = `${API_PATH}/repos/${repoPath}/labels`;\n const res = await forgejoHttp.getJsonUnchecked<Label[]>(url, options);\n\n return res.body;\n}\n\nexport async function getOrgLabels(\n orgName: string,\n options?: ForgejoHttpOptions,\n): Promise<Label[]> {\n const url = `${API_PATH}/orgs/${orgName}/labels`;\n const res = await forgejoHttp.getJsonUnchecked<Label[]>(url, options);\n\n return res.body;\n}\n\nexport async function unassignLabel(\n repoPath: string,\n issue: number,\n label: number,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/labels/${label}`;\n await forgejoHttp.deleteJson(url, options);\n}\n\nexport async function createComment(\n repoPath: string,\n issue: number,\n body: string,\n options?: ForgejoHttpOptions,\n): Promise<Comment> {\n const params: CommentCreateParams = { body };\n const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/comments`;\n const res = await forgejoHttp.postJson<Comment>(url, {\n ...options,\n body: params,\n });\n\n return res.body;\n}\n\nexport async function updateComment(\n repoPath: string,\n idx: number,\n body: string,\n options?: ForgejoHttpOptions,\n): Promise<Comment> {\n const params: CommentUpdateParams = { body };\n const url = `${API_PATH}/repos/${repoPath}/issues/comments/${idx}`;\n const res = await forgejoHttp.patchJson<Comment>(url, {\n ...options,\n body: params,\n });\n\n return res.body;\n}\n\nexport async function deleteComment(\n repoPath: string,\n idx: number,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n const url = `${API_PATH}/repos/${repoPath}/issues/comments/${idx}`;\n await forgejoHttp.deleteJson(url, options);\n}\n\nexport async function getComments(\n repoPath: string,\n issue: number,\n options?: ForgejoHttpOptions,\n): Promise<Comment[]> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/comments`;\n const res = await forgejoHttp.getJsonUnchecked<Comment[]>(url, options);\n\n return res.body;\n}\n\nexport async function createCommitStatus(\n repoPath: string,\n branchCommit: string,\n params: CommitStatusCreateParams,\n options?: ForgejoHttpOptions,\n): Promise<CommitStatus> {\n const url = `${API_PATH}/repos/${repoPath}/statuses/${branchCommit}`;\n const res = await forgejoHttp.postJson<CommitStatus>(url, {\n ...options,\n body: params,\n });\n\n return res.body;\n}\n\nexport const forgejoToRenovateStatusMapping: Record<\n CommitStatusType,\n BranchStatus | null\n> = {\n unknown: 'yellow',\n success: 'green',\n pending: 'yellow',\n warning: 'red',\n failure: 'red',\n error: 'red',\n};\n\nexport const renovateToForgejoStatusMapping: Record<\n BranchStatus,\n CommitStatusType\n> = {\n green: 'success',\n yellow: 'pending',\n red: 'failure',\n};\n\nfunction filterStatus(data: CommitStatus[]): CommitStatus[] {\n const ret: Record<string, CommitStatus> = {};\n for (const i of data) {\n if (!ret[i.context] || ret[i.context].id < i.id) {\n ret[i.context] = i;\n }\n }\n return Object.values(ret);\n}\n\nexport async function getCombinedCommitStatus(\n repoPath: string,\n branchName: string,\n options?: ForgejoHttpOptions,\n): Promise<CombinedCommitStatus> {\n const url = `${API_PATH}/repos/${repoPath}/commits/${urlEscape(\n branchName,\n )}/statuses`;\n const res = await forgejoHttp.getJsonUnchecked<CommitStatus[]>(url, {\n ...options,\n paginate: true,\n });\n\n let worstState = 0;\n const statuses = filterStatus(res.body);\n for (const cs of statuses) {\n worstState = Math.max(worstState, commitStatusStates.indexOf(cs.status));\n }\n\n return {\n worstStatus: commitStatusStates[worstState],\n statuses,\n };\n}\n\nexport async function getBranch(\n repoPath: string,\n branchName: string,\n options?: ForgejoHttpOptions,\n): Promise<Branch> {\n const url = `${API_PATH}/repos/${repoPath}/branches/${urlEscape(branchName)}`;\n const res = await forgejoHttp.getJsonUnchecked<Branch>(url, options);\n\n return res.body;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"forgejo-helper.js","names":[],"sources":["../../../../lib/modules/platform/forgejo/forgejo-helper.ts"],"sourcesContent":["import { isBoolean } from '@sindresorhus/is';\nimport { z } from 'zod/v4';\nimport { logger } from '../../../logger/index.ts';\nimport type { BranchStatus } from '../../../types/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { ForgejoHttpOptions } from '../../../util/http/forgejo.ts';\nimport { ForgejoHttp } from '../../../util/http/forgejo.ts';\nimport { getQueryString } from '../../../util/url.ts';\nimport {\n Branch,\n Comment,\n CommitStatus,\n type CommitStatusType,\n Issue,\n Label,\n PR,\n Repo,\n RepoContents,\n RepoSearchResults,\n User,\n Version,\n} from './schema.ts';\nimport type {\n CombinedCommitStatus,\n CommentCreateParams,\n CommitStatusCreateParams,\n IssueCreateParams,\n IssueSearchParams,\n IssueUpdateLabelsParams,\n IssueUpdateParams,\n PRCreateParams,\n PRMergeParams,\n PRUpdateParams,\n PrReviewersParams,\n RepoSearchParams,\n} from './types.ts';\nimport { API_PATH } from './utils.ts';\n\nexport const forgejoHttp = new ForgejoHttp();\n\nconst urlEscape = (raw: string): string => encodeURIComponent(raw);\nconst commitStatusStates: CommitStatusType[] = [\n 'unknown',\n 'success',\n 'pending',\n 'warning',\n 'failure',\n 'error',\n];\n\nexport async function getCurrentUser(\n options: ForgejoHttpOptions = {},\n): Promise<User> {\n const url = `${API_PATH}/user`;\n const res = await forgejoHttp.getJson(url, options, User);\n return res.body;\n}\n\nexport async function getVersion(\n options: ForgejoHttpOptions = {},\n): Promise<string> {\n const url = `${API_PATH}/version`;\n const res = await forgejoHttp.getJson(url, options, Version);\n return res.body.version;\n}\n\nexport async function isOrg(organization: string): Promise<boolean> {\n const repoCache = getCache();\n repoCache.platform ??= {};\n repoCache.platform.forgejo ??= {};\n repoCache.platform.forgejo.orgs ??= {};\n const cached = repoCache.platform.forgejo.orgs[organization];\n if (isBoolean(cached)) {\n return cached;\n }\n try {\n const url = `${API_PATH}/orgs/${organization}`;\n const res = await forgejoHttp.getJsonUnchecked(url);\n repoCache.platform.forgejo.orgs[organization] = res.statusCode === 200;\n return res.statusCode === 200;\n } catch (err) {\n if (err.statusCode === 404) {\n return false;\n }\n // throw other errors\n throw err;\n }\n}\n\nexport async function searchRepos(\n params: RepoSearchParams,\n options?: ForgejoHttpOptions,\n): Promise<Repo[]> {\n const query = getQueryString(params);\n const url = `${API_PATH}/repos/search?${query}`;\n const res = await forgejoHttp.getJson(\n url,\n {\n ...options,\n paginate: true,\n },\n RepoSearchResults,\n );\n\n if (!res.body.ok) {\n throw new Error(\n 'Unable to search for repositories, ok flag has not been set',\n );\n }\n\n return res.body.data;\n}\n\nexport async function orgListRepos(\n organization: string,\n options?: ForgejoHttpOptions,\n): Promise<Repo[]> {\n const url = `${API_PATH}/orgs/${organization}/repos`;\n const res = await forgejoHttp.getJson(\n url,\n {\n ...options,\n paginate: true,\n },\n z.array(Repo),\n );\n\n return res.body;\n}\n\nexport async function getRepo(\n repoPath: string,\n options: ForgejoHttpOptions = {},\n): Promise<Repo> {\n const url = `${API_PATH}/repos/${repoPath}`;\n const res = await forgejoHttp.getJson(url, options, Repo);\n return res.body;\n}\n\nexport async function getRepoContents(\n repoPath: string,\n filePath: string,\n ref?: string | null,\n options: ForgejoHttpOptions = {},\n): Promise<RepoContents> {\n const query = getQueryString(ref ? { ref } : {});\n const url = `${API_PATH}/repos/${repoPath}/contents/${urlEscape(\n filePath,\n )}?${query}`;\n const res = await forgejoHttp.getJson(url, options, RepoContents);\n\n return res.body;\n}\n\nexport async function createPR(\n repoPath: string,\n params: PRCreateParams,\n options?: ForgejoHttpOptions,\n): Promise<PR> {\n const url = `${API_PATH}/repos/${repoPath}/pulls`;\n const res = await forgejoHttp.postJson(\n url,\n {\n ...options,\n body: params,\n },\n PR,\n );\n\n return res.body;\n}\n\nexport async function updatePR(\n repoPath: string,\n idx: number,\n params: PRUpdateParams,\n options?: ForgejoHttpOptions,\n): Promise<PR> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}`;\n const res = await forgejoHttp.patchJson(\n url,\n {\n ...options,\n body: params,\n },\n PR,\n );\n\n return res.body;\n}\n\nexport async function closePR(\n repoPath: string,\n idx: number,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n await updatePR(repoPath, idx, {\n ...options,\n state: 'closed',\n });\n}\n\nexport async function mergePR(\n repoPath: string,\n idx: number,\n params: PRMergeParams,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}/merge`;\n await forgejoHttp.postJson(url, {\n ...options,\n body: params,\n });\n}\n\nexport async function getPR(\n repoPath: string,\n idx: number,\n options: ForgejoHttpOptions = {},\n): Promise<PR> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}`;\n const res = await forgejoHttp.getJson(url, options, PR);\n return res.body;\n}\n\nexport async function getPRByBranch(\n repoPath: string,\n base: string,\n head: string,\n options: ForgejoHttpOptions = {},\n): Promise<PR | null> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${base}/${head}`;\n try {\n const res = await forgejoHttp.getJson(url, options, PR);\n return res.body;\n } catch (err) {\n logger.trace({ err }, 'Error while fetching PR');\n if (err.statusCode !== 404) {\n logger.debug({ err }, 'Error while fetching PR');\n }\n return null;\n }\n}\n\nexport async function requestPrReviewers(\n repoPath: string,\n idx: number,\n params: PrReviewersParams,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n const url = `${API_PATH}/repos/${repoPath}/pulls/${idx}/requested_reviewers`;\n await forgejoHttp.postJson(url, {\n ...options,\n body: params,\n });\n}\n\nexport async function createIssue(\n repoPath: string,\n params: IssueCreateParams,\n options?: ForgejoHttpOptions,\n): Promise<Issue> {\n const url = `${API_PATH}/repos/${repoPath}/issues`;\n const res = await forgejoHttp.postJson(\n url,\n {\n ...options,\n body: params,\n },\n Issue,\n );\n\n return res.body;\n}\n\nexport async function updateIssue(\n repoPath: string,\n idx: number,\n params: IssueUpdateParams,\n options?: ForgejoHttpOptions,\n): Promise<Issue> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${idx}`;\n const res = await forgejoHttp.patchJson(\n url,\n {\n ...options,\n body: params,\n },\n Issue,\n );\n\n return res.body;\n}\n\nexport async function updateIssueLabels(\n repoPath: string,\n idx: number,\n params: IssueUpdateLabelsParams,\n options?: ForgejoHttpOptions,\n): Promise<Label[]> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${idx}/labels`;\n const res = await forgejoHttp.putJson(\n url,\n {\n ...options,\n body: params,\n },\n z.array(Label),\n );\n\n return res.body;\n}\n\nexport async function closeIssue(\n repoPath: string,\n idx: number,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n await updateIssue(repoPath, idx, {\n ...options,\n state: 'closed',\n });\n}\n\nexport async function searchIssues(\n repoPath: string,\n params: IssueSearchParams,\n options?: ForgejoHttpOptions,\n): Promise<Issue[]> {\n const query = getQueryString({ ...params, type: 'issues' });\n const url = `${API_PATH}/repos/${repoPath}/issues?${query}`;\n const res = await forgejoHttp.getJson(\n url,\n {\n ...options,\n paginate: true,\n },\n z.array(Issue),\n );\n\n return res.body;\n}\n\nexport async function getIssue(\n repoPath: string,\n idx: number,\n options: ForgejoHttpOptions = {},\n): Promise<Issue> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${idx}`;\n const res = await forgejoHttp.getJson(url, options, Issue);\n return res.body;\n}\n\nexport async function getRepoLabels(\n repoPath: string,\n options: ForgejoHttpOptions = {},\n): Promise<Label[]> {\n const url = `${API_PATH}/repos/${repoPath}/labels`;\n const res = await forgejoHttp.getJson(url, options, z.array(Label));\n\n return res.body;\n}\n\nexport async function getOrgLabels(\n orgName: string,\n options: ForgejoHttpOptions = {},\n): Promise<Label[]> {\n const url = `${API_PATH}/orgs/${orgName}/labels`;\n const res = await forgejoHttp.getJson(url, options, z.array(Label));\n\n return res.body;\n}\n\nexport async function unassignLabel(\n repoPath: string,\n issue: number,\n label: number,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/labels/${label}`;\n await forgejoHttp.deleteJson(url, options);\n}\n\nexport async function createComment(\n repoPath: string,\n issue: number,\n body: string,\n options?: ForgejoHttpOptions,\n): Promise<Comment> {\n const params: CommentCreateParams = { body };\n const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/comments`;\n const res = await forgejoHttp.postJson(\n url,\n {\n ...options,\n body: params,\n },\n Comment,\n );\n\n return res.body;\n}\n\nexport async function updateComment(\n repoPath: string,\n idx: number,\n body: string,\n options?: ForgejoHttpOptions,\n): Promise<Comment> {\n const params: CommentCreateParams = { body };\n const url = `${API_PATH}/repos/${repoPath}/issues/comments/${idx}`;\n const res = await forgejoHttp.patchJson(\n url,\n {\n ...options,\n body: params,\n },\n Comment,\n );\n\n return res.body;\n}\n\nexport async function deleteComment(\n repoPath: string,\n idx: number,\n options?: ForgejoHttpOptions,\n): Promise<void> {\n const url = `${API_PATH}/repos/${repoPath}/issues/comments/${idx}`;\n await forgejoHttp.deleteJson(url, options);\n}\n\nexport async function getComments(\n repoPath: string,\n issue: number,\n options: ForgejoHttpOptions = {},\n): Promise<Comment[]> {\n const url = `${API_PATH}/repos/${repoPath}/issues/${issue}/comments`;\n const res = await forgejoHttp.getJson(url, options, z.array(Comment));\n\n return res.body;\n}\n\nexport async function createCommitStatus(\n repoPath: string,\n branchCommit: string,\n params: CommitStatusCreateParams,\n options?: ForgejoHttpOptions,\n): Promise<CommitStatus> {\n const url = `${API_PATH}/repos/${repoPath}/statuses/${branchCommit}`;\n const res = await forgejoHttp.postJson(\n url,\n {\n ...options,\n body: params,\n },\n CommitStatus,\n );\n\n return res.body;\n}\n\nexport const forgejoToRenovateStatusMapping: Record<\n CommitStatusType,\n BranchStatus\n> = {\n unknown: 'yellow',\n success: 'green',\n pending: 'yellow',\n warning: 'red',\n failure: 'red',\n error: 'red',\n};\n\nexport const renovateToForgejoStatusMapping: Record<\n BranchStatus,\n CommitStatusType\n> = {\n green: 'success',\n yellow: 'pending',\n red: 'failure',\n};\n\nfunction filterStatus(data: CommitStatus[]): CommitStatus[] {\n const ret: Record<string, CommitStatus> = {};\n for (const i of data) {\n if (!ret[i.context] || ret[i.context].id < i.id) {\n ret[i.context] = i;\n }\n }\n return Object.values(ret);\n}\n\nexport async function getCombinedCommitStatus(\n repoPath: string,\n branchName: string,\n options?: ForgejoHttpOptions,\n): Promise<CombinedCommitStatus> {\n const url = `${API_PATH}/repos/${repoPath}/commits/${urlEscape(\n branchName,\n )}/statuses`;\n const res = await forgejoHttp.getJson(\n url,\n {\n ...options,\n paginate: true,\n },\n z.array(CommitStatus),\n );\n\n let worstState = 0;\n const statuses = filterStatus(res.body);\n for (const cs of statuses) {\n worstState = Math.max(worstState, commitStatusStates.indexOf(cs.status));\n }\n\n return {\n worstStatus: commitStatusStates[worstState],\n statuses,\n };\n}\n\nexport async function getBranch(\n repoPath: string,\n branchName: string,\n options: ForgejoHttpOptions = {},\n): Promise<Branch> {\n const url = `${API_PATH}/repos/${repoPath}/branches/${urlEscape(branchName)}`;\n const res = await forgejoHttp.getJson(url, options, Branch);\n\n return res.body;\n}\n"],"mappings":"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"}
@@ -150,7 +150,9 @@ const platform = {
150
150
  };
151
151
  },
152
152
  async getRawFile(fileName, repoName, branchOrTag) {
153
- return (await getRepoContents(repoName ?? config.repository, fileName, branchOrTag)).contentString ?? null;
153
+ const contents = await getRepoContents(repoName ?? config.repository, fileName, branchOrTag);
154
+ if (contents.type !== "file") return null;
155
+ return contents.contentString ?? null;
154
156
  },
155
157
  async getJsonFile(fileName, repoName, branchOrTag) {
156
158
  return parseJson(await platform.getRawFile(fileName, repoName, branchOrTag), fileName);
@@ -176,7 +178,7 @@ const platform = {
176
178
  logger.debug("Repository is a mirror - aborting renovation");
177
179
  throw new Error(REPOSITORY_MIRRORED);
178
180
  }
179
- if (repo.permissions.pull === false || repo.permissions.push === false) {
181
+ if (!repo.permissions.pull || !repo.permissions.push) {
180
182
  logger.debug("Repository does not permit pull or push - aborting renovation");
181
183
  throw new Error(REPOSITORY_ACCESS_FORBIDDEN);
182
184
  }
@@ -189,7 +191,7 @@ const platform = {
189
191
  throw new Error(REPOSITORY_BLOCKED);
190
192
  }
191
193
  const mergeStyle = [
192
- repo.default_merge_style,
194
+ ...repo.default_merge_style ? [repo.default_merge_style] : [],
193
195
  "fast-forward-only",
194
196
  "squash",
195
197
  "merge",
@@ -281,16 +283,12 @@ const platform = {
281
283
  logger.debug("Successful checks are all internal renovate/ checks, so returning \"pending\" branch status");
282
284
  return "yellow";
283
285
  }
284
- /* v8 ignore next */
285
- return forgejoToRenovateStatusMapping[ccs.worstStatus] ?? "yellow";
286
+ return forgejoToRenovateStatusMapping[ccs.worstStatus];
286
287
  },
287
288
  async getBranchStatusCheck(branchName, context) {
288
289
  const cs = (await getCombinedCommitStatus(config.repository, branchName)).statuses.find((s) => s.context === context);
289
290
  if (!cs) return null;
290
- const status = forgejoToRenovateStatusMapping[cs.status];
291
- if (status) return status;
292
- logger.warn({ check: cs }, "Could not map Forgejo status value to Renovate status");
293
- return "yellow";
291
+ return forgejoToRenovateStatusMapping[cs.status];
294
292
  },
295
293
  getPrList() {
296
294
  return ForgejoPrCache.getPrs(forgejoHttp, config.repository, config.ignorePrAuthor, botUserName);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["helper\n .getRepoLabels","helper\n .getOrgLabels","helper.searchRepos","helper.getCurrentUser","helper.getVersion","helper.getRepoContents","helper.getRepo","helper.isOrg","git.initRepo","helper.orgListRepos","git.getBranchCommit","helper.createCommitStatus","helper.renovateToForgejoStatusMapping","helper.getCombinedCommitStatus","helper.forgejoToRenovateStatusMapping","helper.getPR","helper.getPRByBranch","helper.createPR","helper.mergePR","helper.updatePR","helper\n .searchIssues","helper.getIssue","helper.closeIssue","helper.updateIssue","helper.updateIssueLabels","helper.createIssue","helper.unassignLabel","helper.getComments","helper.createComment","helper.updateComment","helper.deleteComment","helper.requestPrReviewers"],"sources":["../../../../lib/modules/platform/forgejo/index.ts"],"sourcesContent":["import { isNumber, isString } from '@sindresorhus/is';\nimport semver from 'semver';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport {\n REPOSITORY_ACCESS_FORBIDDEN,\n REPOSITORY_ARCHIVED,\n REPOSITORY_BLOCKED,\n REPOSITORY_CHANGED,\n REPOSITORY_EMPTY,\n REPOSITORY_MIRRORED,\n} from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport type { BranchStatus } from '../../../types/index.ts';\nimport { deduplicateArray } from '../../../util/array.ts';\nimport { parseJson } from '../../../util/common.ts';\nimport { getEnv } from '../../../util/env.ts';\nimport * as git from '../../../util/git/index.ts';\nimport { setBaseUrl } from '../../../util/http/forgejo.ts';\nimport { map } from '../../../util/promises.ts';\nimport { sanitize } from '../../../util/sanitize.ts';\nimport { ensureTrailingSlash } from '../../../util/url.ts';\nimport { getPrBodyStruct, hashBody } from '../pr-body.ts';\nimport type {\n AutodiscoverConfig,\n BranchStatusConfig,\n CreatePRConfig,\n EnsureCommentConfig,\n EnsureCommentRemovalConfig,\n EnsureIssueConfig,\n FindPRConfig,\n Issue,\n MergePRConfig,\n Platform,\n PlatformParams,\n PlatformResult,\n Pr,\n RepoParams,\n RepoResult,\n RepoSortMethod,\n SortMethod,\n UpdatePrConfig,\n} from '../types.ts';\nimport { repoFingerprint } from '../util.ts';\nimport { smartTruncate } from '../utils/pr-body.ts';\nimport * as helper from './forgejo-helper.ts';\nimport { forgejoHttp } from './forgejo-helper.ts';\nimport { ForgejoPrCache } from './pr-cache.ts';\nimport type {\n CombinedCommitStatus,\n Comment,\n Label,\n PRMergeMethod,\n PRUpdateParams,\n Repo,\n} from './types.ts';\nimport {\n DRAFT_PREFIX,\n getMergeMethod,\n getRepoUrl,\n isAllowed,\n smartLinks,\n toRenovatePR,\n trimTrailingApiPath,\n usableRepo,\n} from './utils.ts';\n\ninterface ForgejoRepoConfig {\n ignorePrAuthor: boolean;\n repository: string;\n mergeMethod: PRMergeMethod;\n\n issueList: Promise<Issue[]> | null;\n labelList: Promise<Label[]> | null;\n defaultBranch: string;\n cloneSubmodules: boolean;\n cloneSubmodulesFilter: string[] | undefined;\n hasIssuesEnabled: boolean;\n isOrgRepo: boolean;\n orgName: string;\n}\n\nexport const id = 'forgejo';\n\nconst defaults = {\n hostType: 'forgejo',\n endpoint: 'https://code.forgejo.org/',\n version: '0.0.0',\n};\n\nlet config: ForgejoRepoConfig = {} as any;\nlet botUserID: number;\nlet botUserName: string;\n\nexport function resetPlatform(): void {\n config = {} as any;\n botUserID = undefined as never;\n botUserName = undefined as never;\n defaults.hostType = 'forgejo';\n defaults.endpoint = 'https://code.forgejo.org/';\n defaults.version = '0.0.0';\n setBaseUrl(defaults.endpoint);\n}\n\nfunction toRenovateIssue(data: Issue): Issue {\n return {\n number: data.number,\n state: data.state,\n title: data.title,\n body: data.body,\n };\n}\n\nfunction matchesState(actual: string, expected: string): boolean {\n if (expected === 'all') {\n return true;\n }\n if (expected.startsWith('!')) {\n return actual !== expected.substring(1);\n }\n\n return actual === expected;\n}\n\nfunction findCommentByTopic(\n comments: Comment[],\n topic: string,\n): Comment | null {\n return comments.find((c) => c.body.startsWith(`### ${topic}\\n\\n`)) ?? null;\n}\n\nfunction findCommentByContent(\n comments: Comment[],\n content: string,\n): Comment | null {\n return comments.find((c) => c.body.trim() === content) ?? null;\n}\n\nfunction getLabelList(): Promise<Label[]> {\n if (config.labelList === null) {\n const repoLabels = helper\n .getRepoLabels(config.repository, {\n memCache: false,\n })\n .then((labels) => {\n logger.debug(`Retrieved ${labels.length} repo labels`);\n return labels;\n });\n\n const orgLabels = config.isOrgRepo\n ? helper\n .getOrgLabels(config.orgName, {\n memCache: false,\n })\n .then((labels) => {\n logger.debug(`Retrieved ${labels.length} org labels`);\n return labels;\n })\n .catch((err) => {\n // Will fail if owner of repo is not org\n logger.debug({ err }, `Unable to fetch organization labels`);\n return [] as Label[];\n })\n : Promise.resolve([]);\n\n config.labelList = Promise.all([repoLabels, orgLabels]).then((labels) =>\n ([] as Label[]).concat(...labels),\n );\n }\n\n return config.labelList;\n}\n\nasync function lookupLabelByName(name: string): Promise<number | null> {\n logger.debug(`lookupLabelByName(${name})`);\n const labelList = await getLabelList();\n return labelList.find((l) => l.name === name)?.id ?? null;\n}\n\ninterface FetchRepositoriesArgs {\n topic?: string;\n sort?: RepoSortMethod;\n order?: SortMethod;\n}\n\nasync function fetchRepositories({\n topic,\n sort,\n order,\n}: FetchRepositoriesArgs): Promise<string[]> {\n const repos = await helper.searchRepos({\n uid: botUserID,\n archived: false,\n ...(topic && {\n topic: true,\n q: topic,\n }),\n ...(sort && {\n sort,\n }),\n ...(order && {\n order,\n }),\n });\n return repos.filter(usableRepo).map((r) => r.full_name);\n}\n\nconst platform: Platform = {\n async initPlatform({\n endpoint,\n token,\n }: PlatformParams): Promise<PlatformResult> {\n if (!token) {\n throw new Error(\n 'Init: You must configure a Forgejo personal access token',\n );\n }\n\n if (endpoint) {\n let baseEndpoint = trimTrailingApiPath(endpoint);\n baseEndpoint = ensureTrailingSlash(baseEndpoint);\n defaults.endpoint = baseEndpoint;\n } else {\n logger.debug(`Using default Forgejo endpoint: ${defaults.endpoint}`);\n }\n setBaseUrl(defaults.endpoint);\n\n let gitAuthor: string;\n try {\n const user = await helper.getCurrentUser({ token });\n // oxlint-disable-next-line typescript/prefer-nullish-coalescing -- `full_name` can be emtpy string\n gitAuthor = `${user.full_name || user.login} <${user.email}>`;\n botUserID = user.id;\n botUserName = user.login;\n const env = getEnv();\n /* v8 ignore if: experimental feature */\n if (semver.valid(env.RENOVATE_X_PLATFORM_VERSION)) {\n defaults.version = env.RENOVATE_X_PLATFORM_VERSION!;\n } else {\n defaults.version = await helper.getVersion({ token });\n }\n\n logger.debug(`Forgejo version: ${defaults.version}`);\n } catch (err) {\n logger.debug(\n { err },\n 'Error authenticating with Forgejo. Check your token',\n );\n throw new Error('Init: Authentication failure');\n }\n\n return {\n endpoint: defaults.endpoint,\n gitAuthor,\n };\n },\n\n async getRawFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n ): Promise<string | null> {\n const repo = repoName ?? config.repository;\n const contents = await helper.getRepoContents(repo, fileName, branchOrTag);\n return contents.contentString ?? null;\n },\n\n async getJsonFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n ): Promise<any> {\n // TODO #22198\n const raw = await platform.getRawFile(fileName, repoName, branchOrTag);\n return parseJson(raw, fileName);\n },\n\n async initRepo({\n repository,\n cloneSubmodules,\n cloneSubmodulesFilter,\n gitUrl,\n }: RepoParams): Promise<RepoResult> {\n let repo: Repo;\n\n config = {} as any;\n config.repository = repository;\n config.cloneSubmodules = !!cloneSubmodules;\n config.cloneSubmodulesFilter = cloneSubmodulesFilter;\n config.ignorePrAuthor = GlobalConfig.get('ignorePrAuthor');\n\n // Try to fetch information about repository\n try {\n repo = await helper.getRepo(repository);\n } catch (err) {\n logger.debug({ err }, 'Unknown Forgejo initRepo error');\n throw err;\n }\n\n // Ensure appropriate repository state and permissions\n if (repo.archived) {\n logger.debug('Repository is archived - aborting renovation');\n throw new Error(REPOSITORY_ARCHIVED);\n }\n if (repo.mirror) {\n logger.debug('Repository is a mirror - aborting renovation');\n throw new Error(REPOSITORY_MIRRORED);\n }\n if (repo.permissions.pull === false || repo.permissions.push === false) {\n logger.debug(\n 'Repository does not permit pull or push - aborting renovation',\n );\n throw new Error(REPOSITORY_ACCESS_FORBIDDEN);\n }\n if (repo.empty) {\n logger.debug('Repository is empty - aborting renovation');\n throw new Error(REPOSITORY_EMPTY);\n }\n\n if (repo.has_pull_requests === false) {\n logger.debug('Repo has disabled pull requests - aborting renovation');\n throw new Error(REPOSITORY_BLOCKED);\n }\n\n // similar to forgejo behaviour- if default merge style is allowed, use this;\n // else fall back to predefined order. Order chosen to minimize commits - see\n // https://github.com/renovatebot/renovate/pull/37768 for discussion.\n const preferredOrder: PRMergeMethod[] = [\n repo.default_merge_style,\n 'fast-forward-only',\n 'squash',\n 'merge',\n 'rebase',\n 'rebase-merge',\n ];\n\n const mergeStyle = preferredOrder.find((style) => isAllowed(style, repo));\n\n if (mergeStyle) {\n config.mergeMethod = mergeStyle;\n } else {\n logger.debug(\n 'Repository has no allowed merge methods - aborting renovation',\n );\n throw new Error(REPOSITORY_BLOCKED);\n }\n\n try {\n config.isOrgRepo = await helper.isOrg(repo.owner.login);\n } catch (err) {\n logger.debug({ err }, 'Forgejo initRepo() error');\n throw err;\n }\n\n // Determine author email and branches\n config.defaultBranch = repo.default_branch;\n logger.debug(`${repository} default branch = ${config.defaultBranch}`);\n\n const url = getRepoUrl(repo, gitUrl, defaults.endpoint);\n\n // Initialize Git storage\n await git.initRepo({\n ...config,\n url,\n });\n\n // Reset cached resources\n config.issueList = null;\n config.labelList = null;\n config.hasIssuesEnabled = !repo.external_tracker && repo.has_issues;\n config.orgName = repo.owner.login;\n\n return {\n defaultBranch: config.defaultBranch,\n isFork: !!repo.fork,\n repoFingerprint: repoFingerprint(repo.id, defaults.endpoint),\n };\n },\n\n async getRepos(config?: AutodiscoverConfig): Promise<string[]> {\n logger.debug('Auto-discovering Forgejo repositories');\n try {\n if (config?.topics) {\n logger.debug({ topics: config.topics }, 'Auto-discovering by topics');\n const fetchRepoArgs: FetchRepositoriesArgs[] = config.topics.map(\n (topic) => {\n return {\n topic,\n sort: config.sort,\n order: config.order,\n };\n },\n );\n const repos = await map(fetchRepoArgs, fetchRepositories);\n return deduplicateArray(repos.flat());\n } else if (config?.namespaces) {\n logger.debug(\n { namespaces: config.namespaces },\n 'Auto-discovering by organization',\n );\n const repos = await map(\n config.namespaces,\n async (organization: string) => {\n const orgRepos = await helper.orgListRepos(organization);\n return orgRepos\n .filter((r) => !r.mirror && !r.archived)\n .map((r) => r.full_name);\n },\n );\n return deduplicateArray(repos.flat());\n } else {\n return await fetchRepositories({\n sort: config?.sort,\n order: config?.order,\n });\n }\n } catch (err) {\n logger.error({ err }, 'Forgejo getRepos() error');\n throw err;\n }\n },\n\n async setBranchStatus({\n branchName,\n context,\n description,\n state,\n url: target_url,\n }: BranchStatusConfig): Promise<void> {\n try {\n // Create new status for branch commit\n const branchCommit = git.getBranchCommit(branchName);\n // TODO: check branchCommit\n\n await helper.createCommitStatus(config.repository, branchCommit!, {\n state: helper.renovateToForgejoStatusMapping[state] || 'pending',\n context,\n description,\n ...(target_url && { target_url }),\n });\n\n // Refresh caches by re-fetching commit status for branch\n await helper.getCombinedCommitStatus(config.repository, branchName, {\n memCache: false,\n });\n } catch (err) {\n logger.warn({ err }, 'Failed to set branch status');\n }\n },\n\n async getBranchStatus(\n branchName: string,\n internalChecksAsSuccess: boolean,\n ): Promise<BranchStatus> {\n let ccs: CombinedCommitStatus;\n try {\n ccs = await helper.getCombinedCommitStatus(config.repository, branchName);\n } catch (err) {\n if (err.statusCode === 404) {\n logger.debug(\n 'Received 404 when checking branch status, assuming branch deletion',\n );\n throw new Error(REPOSITORY_CHANGED);\n }\n\n logger.debug('Unknown error when checking branch status');\n throw err;\n }\n\n logger.debug({ ccs }, 'Branch status check result');\n if (\n !internalChecksAsSuccess &&\n ccs.worstStatus === 'success' &&\n ccs.statuses.every((status) => status.context?.startsWith('renovate/'))\n ) {\n logger.debug(\n 'Successful checks are all internal renovate/ checks, so returning \"pending\" branch status',\n );\n return 'yellow';\n }\n\n /* v8 ignore next */\n return helper.forgejoToRenovateStatusMapping[ccs.worstStatus] ?? 'yellow';\n },\n\n async getBranchStatusCheck(\n branchName: string,\n context: string,\n ): Promise<BranchStatus | null> {\n const ccs = await helper.getCombinedCommitStatus(\n config.repository,\n branchName,\n );\n const cs = ccs.statuses.find((s) => s.context === context);\n if (!cs) {\n return null;\n } // no status check exists\n const status = helper.forgejoToRenovateStatusMapping[cs.status];\n if (status) {\n return status;\n }\n logger.warn(\n { check: cs },\n 'Could not map Forgejo status value to Renovate status',\n );\n return 'yellow';\n },\n\n getPrList(): Promise<Pr[]> {\n return ForgejoPrCache.getPrs(\n forgejoHttp,\n config.repository,\n config.ignorePrAuthor,\n botUserName,\n );\n },\n\n async getPr(number: number): Promise<Pr | null> {\n // Search for pull request in cached list or attempt to query directly\n const prList = await platform.getPrList();\n let pr = prList.find((p) => p.number === number) ?? null;\n if (pr) {\n logger.debug('Returning from cached PRs');\n } else {\n logger.debug('PR not found in cached PRs - trying to fetch directly');\n const gpr = await helper.getPR(config.repository, number);\n pr = toRenovatePR(gpr, botUserName);\n\n // Add pull request to cache for further lookups / queries\n if (pr) {\n await ForgejoPrCache.setPr(\n forgejoHttp,\n config.repository,\n config.ignorePrAuthor,\n botUserName,\n pr,\n );\n }\n }\n\n // Abort and return null if no match was found\n if (!pr) {\n return null;\n }\n\n return pr;\n },\n\n async findPr({\n branchName,\n prTitle: title,\n state = 'all',\n includeOtherAuthors,\n targetBranch,\n }: FindPRConfig): Promise<Pr | null> {\n logger.debug(`findPr(${branchName}, ${title!}, ${state})`);\n if (includeOtherAuthors && isString(targetBranch)) {\n // do not use pr cache as it only fetches prs created by the bot account\n const pr = await helper.getPRByBranch(\n config.repository,\n targetBranch,\n branchName,\n );\n if (!pr) {\n return null;\n }\n\n return toRenovatePR(pr, null);\n }\n const prList = await platform.getPrList();\n const pr = prList.find(\n (p) =>\n p.sourceRepo === config.repository &&\n p.sourceBranch === branchName &&\n matchesState(p.state, state) &&\n (!title || p.title === title),\n );\n\n if (pr) {\n logger.debug(`Found PR #${pr.number}`);\n }\n return pr ?? null;\n },\n\n async createPr({\n sourceBranch,\n targetBranch,\n prTitle,\n prBody: rawBody,\n labels: labelNames,\n platformPrOptions,\n draftPR,\n }: CreatePRConfig): Promise<Pr> {\n let title = prTitle;\n const base = targetBranch;\n const head = sourceBranch;\n const body = sanitize(rawBody);\n if (draftPR) {\n title = DRAFT_PREFIX + title;\n }\n\n logger.debug(`Creating pull request: ${title} (${head} => ${base})`);\n try {\n const labels = Array.isArray(labelNames)\n ? await map(labelNames, lookupLabelByName)\n : [];\n const gpr = await helper.createPR(config.repository, {\n base,\n head,\n title,\n body,\n labels: labels.filter(isNumber),\n });\n\n if (platformPrOptions?.usePlatformAutomerge) {\n // Only Forgejo v10.0.0+ support delete_branch_after_merge.\n // This is required to not have undesired behavior when renovate finds existing branches on next run.\n // Codeberg usees git versioning like `11.0.1-99-c504062+gitea-1.22.0` so allow any version >= 10.0.0-0.\n if (semver.gte(defaults.version, '10.0.0-0')) {\n try {\n await helper.mergePR(config.repository, gpr.number, {\n Do:\n getMergeMethod(platformPrOptions?.automergeStrategy) ??\n config.mergeMethod,\n merge_when_checks_succeed: true,\n delete_branch_after_merge: true,\n });\n\n logger.debug(\n { prNumber: gpr.number },\n 'Forgejo-native automerge: success',\n );\n } catch (err) {\n logger.warn(\n { err, prNumber: gpr.number },\n 'Forgejo-native automerge: fail',\n );\n }\n } else {\n logger.debug(\n { prNumber: gpr.number },\n `Forgejo-native automerge: not supported on this version of Forgejo. Use 10.0.0 or newer.`,\n );\n }\n }\n\n const pr = toRenovatePR(gpr, botUserName);\n if (!pr) {\n throw new Error('Can not parse newly created Pull Request');\n }\n\n await ForgejoPrCache.setPr(\n forgejoHttp,\n config.repository,\n config.ignorePrAuthor,\n botUserName,\n pr,\n );\n return pr;\n } catch (err) {\n // When the user manually deletes a branch from Renovate, the PR remains but is no longer linked to any branch. In\n // the most recent versions of Forgejo, the PR gets automatically closed when that happens, but older versions do\n // not handle this properly and keep the PR open. As pushing a branch with the same name resurrects the PR, this\n // would cause a HTTP 409 conflict error, which we hereby gracefully handle.\n if (err.statusCode === 409) {\n logger.warn(\n { prTitle: title, sourceBranch },\n 'Attempting to gracefully recover from 409 Conflict response in createPr()',\n );\n\n // Refresh cached PR list and search for pull request with matching information\n ForgejoPrCache.forceSync();\n const pr = await platform.findPr({\n branchName: sourceBranch,\n state: 'open',\n });\n\n // If a valid PR was found, return and gracefully recover from the error. Otherwise, abort and throw error.\n // v8 ignore else -- TODO: add test #40625\n if (pr?.bodyStruct) {\n if (pr.title !== title || pr.bodyStruct.hash !== hashBody(body)) {\n logger.debug(\n `Recovered from 409 Conflict, but PR for ${sourceBranch} is outdated. Updating...`,\n );\n await platform.updatePr({\n number: pr.number,\n prTitle: title,\n prBody: body,\n });\n pr.title = title;\n pr.bodyStruct = getPrBodyStruct(body);\n } else {\n logger.debug(\n `Recovered from 409 Conflict and PR for ${sourceBranch} is up-to-date`,\n );\n }\n\n return pr;\n }\n }\n\n throw err;\n }\n },\n\n async updatePr({\n number,\n prTitle,\n prBody: body,\n labels,\n state,\n targetBranch,\n }: UpdatePrConfig): Promise<void> {\n let title = prTitle;\n if ((await getPrList()).find((pr) => pr.number === number)?.isDraft) {\n title = DRAFT_PREFIX + title;\n }\n\n const prUpdateParams: PRUpdateParams = {\n title,\n ...(body && { body }),\n ...(state && { state }),\n };\n if (targetBranch) {\n prUpdateParams.base = targetBranch;\n }\n\n /**\n * Update PR labels.\n * In the Forgejo API, labels are replaced on each update if the field is present.\n * If the field is not present (i.e., undefined), labels aren't updated.\n * However, the labels array must contain label IDs instead of names,\n * so a lookup is performed to fetch the details (including the ID) of each label.\n */\n if (Array.isArray(labels)) {\n prUpdateParams.labels = (await map(labels, lookupLabelByName)).filter(\n isNumber,\n );\n if (labels.length !== prUpdateParams.labels.length) {\n logger.warn(\n 'Some labels could not be looked up. Renovate may halt label updates assuming changes by others.',\n );\n }\n }\n\n const gpr = await helper.updatePR(\n config.repository,\n number,\n prUpdateParams,\n );\n const pr = toRenovatePR(gpr, botUserName);\n if (pr) {\n await ForgejoPrCache.setPr(\n forgejoHttp,\n config.repository,\n config.ignorePrAuthor,\n botUserName,\n pr,\n );\n }\n },\n\n async mergePr({ id, strategy }: MergePRConfig): Promise<boolean> {\n try {\n await helper.mergePR(config.repository, id, {\n Do: getMergeMethod(strategy) ?? config.mergeMethod,\n });\n return true;\n } catch (err) {\n logger.warn({ err, id }, 'Merging of PR failed');\n return false;\n }\n },\n\n getIssueList(): Promise<Issue[]> {\n if (config.hasIssuesEnabled === false) {\n return Promise.resolve([]);\n }\n config.issueList ??= helper\n .searchIssues(config.repository, { state: 'all' }, { memCache: false })\n .then((issues) => {\n const issueList = issues.map(toRenovateIssue);\n logger.debug(`Retrieved ${issueList.length} Issues`);\n return issueList;\n });\n\n return config.issueList;\n },\n\n async getIssue(number: number, memCache = true): Promise<Issue | null> {\n if (config.hasIssuesEnabled === false) {\n return null;\n }\n try {\n const body = (\n await helper.getIssue(config.repository, number, { memCache })\n ).body;\n return {\n number,\n body,\n };\n } catch (err) {\n logger.debug({ err, number }, 'Error getting issue');\n return null;\n }\n },\n\n async findIssue(title: string): Promise<Issue | null> {\n const issueList = await platform.getIssueList();\n const issue = issueList.find(\n (i) => i.state === 'open' && i.title === title,\n );\n\n if (!issue) {\n return null;\n }\n // TODO: types (#22198)\n logger.debug(`Found Issue #${issue.number!}`);\n // TODO #22198\n return getIssue!(issue.number!);\n },\n\n async ensureIssue({\n title,\n reuseTitle,\n body: content,\n labels: labelNames,\n shouldReOpen,\n once,\n }: EnsureIssueConfig): Promise<'updated' | 'created' | null> {\n logger.debug(`ensureIssue(${title})`);\n if (config.hasIssuesEnabled === false) {\n logger.info(\n 'Cannot ensure issue because issues are disabled in this repository',\n );\n return null;\n }\n try {\n const body = smartLinks(content);\n\n const issueList = await platform.getIssueList();\n let issues = issueList.filter((i) => i.title === title);\n if (!issues.length) {\n issues = issueList.filter((i) => i.title === reuseTitle);\n }\n\n const labels = Array.isArray(labelNames)\n ? (await Promise.all(labelNames.map(lookupLabelByName))).filter(\n isNumber,\n )\n : undefined;\n\n // Update any matching issues which currently exist\n if (issues.length) {\n let activeIssue = issues.find((i) => i.state === 'open');\n\n // If no active issue was found, decide if it shall be skipped, re-opened or updated without state change\n if (!activeIssue) {\n if (once) {\n logger.debug('Issue already closed - skipping update');\n return null;\n }\n if (shouldReOpen) {\n logger.debug('Reopening previously closed Issue');\n }\n\n // Pick the last issue in the list as the active one\n activeIssue = issues[issues.length - 1];\n }\n\n // Close any duplicate issues\n for (const issue of issues) {\n if (issue.state === 'open' && issue.number !== activeIssue.number) {\n // TODO: types (#22198)\n logger.warn({ issueNo: issue.number! }, 'Closing duplicate issue');\n // TODO #22198\n await helper.closeIssue(config.repository, issue.number!);\n }\n }\n\n // Check if issue has already correct state\n if (\n activeIssue.title === title &&\n activeIssue.body === body &&\n activeIssue.state === 'open'\n ) {\n logger.debug(\n // TODO: types (#22198)\n `Issue #${activeIssue.number!} is open and up to date - nothing to do`,\n );\n return null;\n }\n\n if (shouldReOpen || activeIssue.state === 'open') {\n // Update issue body and re-open\n logger.debug(`Updating Issue #${activeIssue.number}`);\n const existingIssue = await helper.updateIssue(\n config.repository,\n // TODO #22198\n activeIssue.number!,\n {\n body,\n title,\n state: 'open',\n },\n );\n\n // Test whether the issues need to be updated\n const existingLabelIds = (existingIssue.labels ?? []).map(\n (label) => label.id,\n );\n if (\n labels &&\n (labels.length !== existingLabelIds.length ||\n labels.filter((labelId) => !existingLabelIds.includes(labelId))\n .length !== 0)\n ) {\n await helper.updateIssueLabels(\n config.repository,\n // TODO #22198\n activeIssue.number!,\n {\n labels,\n },\n );\n }\n\n return 'updated';\n }\n }\n\n // Create new issue and reset cache\n const issue = await helper.createIssue(config.repository, {\n body,\n title,\n labels,\n });\n logger.debug(`Created new Issue #${issue.number}`);\n config.issueList = null;\n\n return 'created';\n } catch (err) {\n logger.warn({ err }, 'Could not ensure issue');\n }\n\n return null;\n },\n\n async ensureIssueClosing(title: string): Promise<void> {\n logger.debug(`ensureIssueClosing(${title})`);\n if (config.hasIssuesEnabled === false) {\n return;\n }\n const issueList = await platform.getIssueList();\n for (const issue of issueList) {\n if (issue.state === 'open' && issue.title === title) {\n logger.debug(`Closing issue...issueNo: ${issue.number!}`);\n // TODO #22198\n await helper.closeIssue(config.repository, issue.number!);\n }\n }\n },\n\n async deleteLabel(issue: number, labelName: string): Promise<void> {\n logger.debug(`Deleting label ${labelName} from Issue #${issue}`);\n const label = await lookupLabelByName(labelName);\n if (label) {\n await helper.unassignLabel(config.repository, issue, label);\n } else {\n logger.warn({ issue, labelName }, 'Failed to lookup label for deletion');\n }\n },\n\n async ensureComment({\n number: issue,\n topic,\n content,\n }: EnsureCommentConfig): Promise<boolean> {\n try {\n let body = sanitize(content);\n const commentList = await helper.getComments(config.repository, issue);\n\n // Search comment by either topic or exact body\n let comment: Comment | null = null;\n if (topic) {\n comment = findCommentByTopic(commentList, topic);\n body = `### ${topic}\\n\\n${body}`;\n } else {\n comment = findCommentByContent(commentList, body);\n }\n\n // Create a new comment if no match has been found, otherwise update if necessary\n if (!comment) {\n comment = await helper.createComment(config.repository, issue, body);\n logger.info(\n { repository: config.repository, issue, comment: comment.id },\n 'Comment added',\n );\n } else if (comment.body === body) {\n logger.debug(`Comment #${comment.id} is already up-to-date`);\n } else {\n await helper.updateComment(config.repository, comment.id, body);\n logger.debug(\n { repository: config.repository, issue, comment: comment.id },\n 'Comment updated',\n );\n }\n\n return true;\n } catch (err) {\n logger.warn({ err, issue, subject: topic }, 'Error ensuring comment');\n return false;\n }\n },\n\n async ensureCommentRemoval(\n deleteConfig: EnsureCommentRemovalConfig,\n ): Promise<void> {\n const { number: issue } = deleteConfig;\n const key =\n deleteConfig.type === 'by-topic'\n ? deleteConfig.topic\n : deleteConfig.content;\n logger.debug(`Ensuring comment \"${key}\" in #${issue} is removed`);\n const commentList = await helper.getComments(config.repository, issue);\n\n let comment: Comment | null = null;\n // v8 ignore else -- TODO: add test #40625\n if (deleteConfig.type === 'by-topic') {\n comment = findCommentByTopic(commentList, deleteConfig.topic);\n } else if (deleteConfig.type === 'by-content') {\n const body = sanitize(deleteConfig.content);\n comment = findCommentByContent(commentList, body);\n }\n\n // Abort and do nothing if no matching comment was found\n if (!comment) {\n return;\n }\n\n // Try to delete comment\n try {\n await helper.deleteComment(config.repository, comment.id);\n } catch (err) {\n logger.warn(\n { err, issue, config: deleteConfig },\n 'Error deleting comment',\n );\n }\n },\n\n async getBranchPr(branchName: string): Promise<Pr | null> {\n logger.debug(`getBranchPr(${branchName})`);\n const pr = await platform.findPr({ branchName, state: 'open' });\n return pr ? platform.getPr(pr.number) : null;\n },\n\n async addAssignees(number: number, assignees: string[]): Promise<void> {\n logger.debug(\n `Updating assignees '${assignees?.join(', ')}' on Issue #${number}`,\n );\n await helper.updateIssue(config.repository, number, {\n assignees,\n });\n },\n\n async addReviewers(number: number, reviewers: string[]): Promise<void> {\n logger.debug(`Adding reviewers '${reviewers?.join(', ')}' to #${number}`);\n try {\n const teamReviewers = new Set(\n reviewers\n .filter((r) => r.startsWith('team:'))\n .map((r) => r.substring(5)),\n );\n const userReviewers = new Set(\n reviewers.filter((r) => !r.startsWith('team:')),\n );\n\n await helper.requestPrReviewers(config.repository, number, {\n reviewers: [...userReviewers],\n ...(teamReviewers.size && {\n team_reviewers: [...teamReviewers],\n }),\n });\n } catch (err) {\n logger.warn({ err, number, reviewers }, 'Failed to assign reviewer');\n }\n },\n\n massageMarkdown(prBody: string): string {\n return smartTruncate(smartLinks(prBody), maxBodyLength());\n },\n\n maxBodyLength,\n};\n\nexport function maxBodyLength(): number {\n return 1000000;\n}\n\n/* oxlint-disable typescript/unbound-method */\nexport const {\n addAssignees,\n addReviewers,\n createPr,\n deleteLabel,\n ensureComment,\n ensureCommentRemoval,\n ensureIssue,\n ensureIssueClosing,\n findIssue,\n findPr,\n getBranchPr,\n getBranchStatus,\n getBranchStatusCheck,\n getIssue,\n getRawFile,\n getJsonFile,\n getIssueList,\n getPr,\n massageMarkdown,\n getPrList,\n getRepos,\n initPlatform,\n initRepo,\n mergePr,\n setBranchStatus,\n updatePr,\n} = platform;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["helper\n .getRepoLabels","helper\n .getOrgLabels","helper.searchRepos","helper.getCurrentUser","helper.getVersion","helper.getRepoContents","helper.getRepo","helper.isOrg","git.initRepo","helper.orgListRepos","git.getBranchCommit","helper.createCommitStatus","helper.renovateToForgejoStatusMapping","helper.getCombinedCommitStatus","helper.forgejoToRenovateStatusMapping","helper.getPR","helper.getPRByBranch","helper.createPR","helper.mergePR","helper.updatePR","helper\n .searchIssues","helper.getIssue","helper.closeIssue","helper.updateIssue","helper.updateIssueLabels","helper.createIssue","helper.unassignLabel","helper.getComments","helper.createComment","helper.updateComment","helper.deleteComment","helper.requestPrReviewers"],"sources":["../../../../lib/modules/platform/forgejo/index.ts"],"sourcesContent":["import { isNumber, isString } from '@sindresorhus/is';\nimport semver from 'semver';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport {\n REPOSITORY_ACCESS_FORBIDDEN,\n REPOSITORY_ARCHIVED,\n REPOSITORY_BLOCKED,\n REPOSITORY_CHANGED,\n REPOSITORY_EMPTY,\n REPOSITORY_MIRRORED,\n} from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport type { BranchStatus } from '../../../types/index.ts';\nimport { deduplicateArray } from '../../../util/array.ts';\nimport { parseJson } from '../../../util/common.ts';\nimport { getEnv } from '../../../util/env.ts';\nimport * as git from '../../../util/git/index.ts';\nimport { setBaseUrl } from '../../../util/http/forgejo.ts';\nimport { map } from '../../../util/promises.ts';\nimport { sanitize } from '../../../util/sanitize.ts';\nimport { ensureTrailingSlash } from '../../../util/url.ts';\nimport { getPrBodyStruct, hashBody } from '../pr-body.ts';\nimport type {\n AutodiscoverConfig,\n BranchStatusConfig,\n CreatePRConfig,\n EnsureCommentConfig,\n EnsureCommentRemovalConfig,\n EnsureIssueConfig,\n FindPRConfig,\n Issue,\n MergePRConfig,\n Platform,\n PlatformParams,\n PlatformResult,\n Pr,\n RepoParams,\n RepoResult,\n RepoSortMethod,\n SortMethod,\n UpdatePrConfig,\n} from '../types.ts';\nimport { repoFingerprint } from '../util.ts';\nimport { smartTruncate } from '../utils/pr-body.ts';\nimport * as helper from './forgejo-helper.ts';\nimport { forgejoHttp } from './forgejo-helper.ts';\nimport { ForgejoPrCache } from './pr-cache.ts';\nimport type { Comment, Label, PRMergeMethod, Repo } from './schema.ts';\nimport type { CombinedCommitStatus, PRUpdateParams } from './types.ts';\nimport {\n DRAFT_PREFIX,\n getMergeMethod,\n getRepoUrl,\n isAllowed,\n smartLinks,\n toRenovatePR,\n trimTrailingApiPath,\n usableRepo,\n} from './utils.ts';\n\ninterface ForgejoRepoConfig {\n ignorePrAuthor: boolean;\n repository: string;\n mergeMethod: PRMergeMethod;\n\n issueList: Promise<Issue[]> | null;\n labelList: Promise<Label[]> | null;\n defaultBranch: string;\n cloneSubmodules: boolean;\n cloneSubmodulesFilter: string[] | undefined;\n hasIssuesEnabled: boolean;\n isOrgRepo: boolean;\n orgName: string;\n}\n\nexport const id = 'forgejo';\n\nconst defaults = {\n hostType: 'forgejo',\n endpoint: 'https://code.forgejo.org/',\n version: '0.0.0',\n};\n\nlet config: ForgejoRepoConfig = {} as any;\nlet botUserID: number;\nlet botUserName: string;\n\nexport function resetPlatform(): void {\n config = {} as any;\n botUserID = undefined as never;\n botUserName = undefined as never;\n defaults.hostType = 'forgejo';\n defaults.endpoint = 'https://code.forgejo.org/';\n defaults.version = '0.0.0';\n setBaseUrl(defaults.endpoint);\n}\n\nfunction toRenovateIssue(data: Issue): Issue {\n return {\n number: data.number,\n state: data.state,\n title: data.title,\n body: data.body,\n };\n}\n\nfunction matchesState(actual: string, expected: string): boolean {\n if (expected === 'all') {\n return true;\n }\n if (expected.startsWith('!')) {\n return actual !== expected.substring(1);\n }\n\n return actual === expected;\n}\n\nfunction findCommentByTopic(\n comments: Comment[],\n topic: string,\n): Comment | null {\n return comments.find((c) => c.body.startsWith(`### ${topic}\\n\\n`)) ?? null;\n}\n\nfunction findCommentByContent(\n comments: Comment[],\n content: string,\n): Comment | null {\n return comments.find((c) => c.body.trim() === content) ?? null;\n}\n\nfunction getLabelList(): Promise<Label[]> {\n if (config.labelList === null) {\n const repoLabels = helper\n .getRepoLabels(config.repository, {\n memCache: false,\n })\n .then((labels) => {\n logger.debug(`Retrieved ${labels.length} repo labels`);\n return labels;\n });\n\n const orgLabels = config.isOrgRepo\n ? helper\n .getOrgLabels(config.orgName, {\n memCache: false,\n })\n .then((labels) => {\n logger.debug(`Retrieved ${labels.length} org labels`);\n return labels;\n })\n .catch((err) => {\n // Will fail if owner of repo is not org\n logger.debug({ err }, `Unable to fetch organization labels`);\n return [] as Label[];\n })\n : Promise.resolve([]);\n\n config.labelList = Promise.all([repoLabels, orgLabels]).then((labels) =>\n ([] as Label[]).concat(...labels),\n );\n }\n\n return config.labelList;\n}\n\nasync function lookupLabelByName(name: string): Promise<number | null> {\n logger.debug(`lookupLabelByName(${name})`);\n const labelList = await getLabelList();\n return labelList.find((l) => l.name === name)?.id ?? null;\n}\n\ninterface FetchRepositoriesArgs {\n topic?: string;\n sort?: RepoSortMethod;\n order?: SortMethod;\n}\n\nasync function fetchRepositories({\n topic,\n sort,\n order,\n}: FetchRepositoriesArgs): Promise<string[]> {\n const repos = await helper.searchRepos({\n uid: botUserID,\n archived: false,\n ...(topic && {\n topic: true,\n q: topic,\n }),\n ...(sort && {\n sort,\n }),\n ...(order && {\n order,\n }),\n });\n return repos.filter(usableRepo).map((r) => r.full_name);\n}\n\nconst platform: Platform = {\n async initPlatform({\n endpoint,\n token,\n }: PlatformParams): Promise<PlatformResult> {\n if (!token) {\n throw new Error(\n 'Init: You must configure a Forgejo personal access token',\n );\n }\n\n if (endpoint) {\n let baseEndpoint = trimTrailingApiPath(endpoint);\n baseEndpoint = ensureTrailingSlash(baseEndpoint);\n defaults.endpoint = baseEndpoint;\n } else {\n logger.debug(`Using default Forgejo endpoint: ${defaults.endpoint}`);\n }\n setBaseUrl(defaults.endpoint);\n\n let gitAuthor: string;\n try {\n const user = await helper.getCurrentUser({ token });\n // oxlint-disable-next-line typescript/prefer-nullish-coalescing -- `full_name` can be emtpy string\n gitAuthor = `${user.full_name || user.login} <${user.email}>`;\n botUserID = user.id;\n botUserName = user.login;\n const env = getEnv();\n /* v8 ignore if: experimental feature */\n if (semver.valid(env.RENOVATE_X_PLATFORM_VERSION)) {\n defaults.version = env.RENOVATE_X_PLATFORM_VERSION!;\n } else {\n defaults.version = await helper.getVersion({ token });\n }\n\n logger.debug(`Forgejo version: ${defaults.version}`);\n } catch (err) {\n logger.debug(\n { err },\n 'Error authenticating with Forgejo. Check your token',\n );\n throw new Error('Init: Authentication failure');\n }\n\n return {\n endpoint: defaults.endpoint,\n gitAuthor,\n };\n },\n\n async getRawFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n ): Promise<string | null> {\n const repo = repoName ?? config.repository;\n const contents = await helper.getRepoContents(repo, fileName, branchOrTag);\n if (contents.type !== 'file') {\n return null;\n }\n return contents.contentString ?? null;\n },\n\n async getJsonFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n ): Promise<any> {\n // TODO #22198\n const raw = await platform.getRawFile(fileName, repoName, branchOrTag);\n return parseJson(raw, fileName);\n },\n\n async initRepo({\n repository,\n cloneSubmodules,\n cloneSubmodulesFilter,\n gitUrl,\n }: RepoParams): Promise<RepoResult> {\n let repo: Repo;\n\n config = {} as any;\n config.repository = repository;\n config.cloneSubmodules = !!cloneSubmodules;\n config.cloneSubmodulesFilter = cloneSubmodulesFilter;\n config.ignorePrAuthor = GlobalConfig.get('ignorePrAuthor');\n\n // Try to fetch information about repository\n try {\n repo = await helper.getRepo(repository);\n } catch (err) {\n logger.debug({ err }, 'Unknown Forgejo initRepo error');\n throw err;\n }\n\n // Ensure appropriate repository state and permissions\n if (repo.archived) {\n logger.debug('Repository is archived - aborting renovation');\n throw new Error(REPOSITORY_ARCHIVED);\n }\n if (repo.mirror) {\n logger.debug('Repository is a mirror - aborting renovation');\n throw new Error(REPOSITORY_MIRRORED);\n }\n if (!repo.permissions.pull || !repo.permissions.push) {\n logger.debug(\n 'Repository does not permit pull or push - aborting renovation',\n );\n throw new Error(REPOSITORY_ACCESS_FORBIDDEN);\n }\n if (repo.empty) {\n logger.debug('Repository is empty - aborting renovation');\n throw new Error(REPOSITORY_EMPTY);\n }\n\n if (repo.has_pull_requests === false) {\n logger.debug('Repo has disabled pull requests - aborting renovation');\n throw new Error(REPOSITORY_BLOCKED);\n }\n\n // similar to forgejo behaviour- if default merge style is allowed, use this;\n // else fall back to predefined order. Order chosen to minimize commits - see\n // https://github.com/renovatebot/renovate/pull/37768 for discussion.\n const preferredOrder: PRMergeMethod[] = [\n ...(repo.default_merge_style ? [repo.default_merge_style] : []),\n 'fast-forward-only',\n 'squash',\n 'merge',\n 'rebase',\n 'rebase-merge',\n ];\n\n const mergeStyle = preferredOrder.find((style) => isAllowed(style, repo));\n\n if (mergeStyle) {\n config.mergeMethod = mergeStyle;\n } else {\n logger.debug(\n 'Repository has no allowed merge methods - aborting renovation',\n );\n throw new Error(REPOSITORY_BLOCKED);\n }\n\n try {\n config.isOrgRepo = await helper.isOrg(repo.owner.login);\n } catch (err) {\n logger.debug({ err }, 'Forgejo initRepo() error');\n throw err;\n }\n\n // Determine author email and branches\n config.defaultBranch = repo.default_branch;\n logger.debug(`${repository} default branch = ${config.defaultBranch}`);\n\n const url = getRepoUrl(repo, gitUrl, defaults.endpoint);\n\n // Initialize Git storage\n await git.initRepo({\n ...config,\n url,\n });\n\n // Reset cached resources\n config.issueList = null;\n config.labelList = null;\n config.hasIssuesEnabled = !repo.external_tracker && repo.has_issues;\n config.orgName = repo.owner.login;\n\n return {\n defaultBranch: config.defaultBranch,\n isFork: !!repo.fork,\n repoFingerprint: repoFingerprint(repo.id, defaults.endpoint),\n };\n },\n\n async getRepos(config?: AutodiscoverConfig): Promise<string[]> {\n logger.debug('Auto-discovering Forgejo repositories');\n try {\n if (config?.topics) {\n logger.debug({ topics: config.topics }, 'Auto-discovering by topics');\n const fetchRepoArgs: FetchRepositoriesArgs[] = config.topics.map(\n (topic) => {\n return {\n topic,\n sort: config.sort,\n order: config.order,\n };\n },\n );\n const repos = await map(fetchRepoArgs, fetchRepositories);\n return deduplicateArray(repos.flat());\n } else if (config?.namespaces) {\n logger.debug(\n { namespaces: config.namespaces },\n 'Auto-discovering by organization',\n );\n const repos = await map(\n config.namespaces,\n async (organization: string) => {\n const orgRepos = await helper.orgListRepos(organization);\n return orgRepos\n .filter((r) => !r.mirror && !r.archived)\n .map((r) => r.full_name);\n },\n );\n return deduplicateArray(repos.flat());\n } else {\n return await fetchRepositories({\n sort: config?.sort,\n order: config?.order,\n });\n }\n } catch (err) {\n logger.error({ err }, 'Forgejo getRepos() error');\n throw err;\n }\n },\n\n async setBranchStatus({\n branchName,\n context,\n description,\n state,\n url: target_url,\n }: BranchStatusConfig): Promise<void> {\n try {\n // Create new status for branch commit\n const branchCommit = git.getBranchCommit(branchName);\n // TODO: check branchCommit\n\n await helper.createCommitStatus(config.repository, branchCommit!, {\n state: helper.renovateToForgejoStatusMapping[state] || 'pending',\n context,\n description,\n ...(target_url && { target_url }),\n });\n\n // Refresh caches by re-fetching commit status for branch\n await helper.getCombinedCommitStatus(config.repository, branchName, {\n memCache: false,\n });\n } catch (err) {\n logger.warn({ err }, 'Failed to set branch status');\n }\n },\n\n async getBranchStatus(\n branchName: string,\n internalChecksAsSuccess: boolean,\n ): Promise<BranchStatus> {\n let ccs: CombinedCommitStatus;\n try {\n ccs = await helper.getCombinedCommitStatus(config.repository, branchName);\n } catch (err) {\n if (err.statusCode === 404) {\n logger.debug(\n 'Received 404 when checking branch status, assuming branch deletion',\n );\n throw new Error(REPOSITORY_CHANGED);\n }\n\n logger.debug('Unknown error when checking branch status');\n throw err;\n }\n\n logger.debug({ ccs }, 'Branch status check result');\n if (\n !internalChecksAsSuccess &&\n ccs.worstStatus === 'success' &&\n ccs.statuses.every((status) => status.context?.startsWith('renovate/'))\n ) {\n logger.debug(\n 'Successful checks are all internal renovate/ checks, so returning \"pending\" branch status',\n );\n return 'yellow';\n }\n\n return helper.forgejoToRenovateStatusMapping[ccs.worstStatus];\n },\n\n async getBranchStatusCheck(\n branchName: string,\n context: string,\n ): Promise<BranchStatus | null> {\n const ccs = await helper.getCombinedCommitStatus(\n config.repository,\n branchName,\n );\n const cs = ccs.statuses.find((s) => s.context === context);\n if (!cs) {\n return null;\n } // no status check exists\n return helper.forgejoToRenovateStatusMapping[cs.status];\n },\n\n getPrList(): Promise<Pr[]> {\n return ForgejoPrCache.getPrs(\n forgejoHttp,\n config.repository,\n config.ignorePrAuthor,\n botUserName,\n );\n },\n\n async getPr(number: number): Promise<Pr | null> {\n // Search for pull request in cached list or attempt to query directly\n const prList = await platform.getPrList();\n let pr = prList.find((p) => p.number === number) ?? null;\n if (pr) {\n logger.debug('Returning from cached PRs');\n } else {\n logger.debug('PR not found in cached PRs - trying to fetch directly');\n const gpr = await helper.getPR(config.repository, number);\n pr = toRenovatePR(gpr, botUserName);\n\n // Add pull request to cache for further lookups / queries\n if (pr) {\n await ForgejoPrCache.setPr(\n forgejoHttp,\n config.repository,\n config.ignorePrAuthor,\n botUserName,\n pr,\n );\n }\n }\n\n // Abort and return null if no match was found\n if (!pr) {\n return null;\n }\n\n return pr;\n },\n\n async findPr({\n branchName,\n prTitle: title,\n state = 'all',\n includeOtherAuthors,\n targetBranch,\n }: FindPRConfig): Promise<Pr | null> {\n logger.debug(`findPr(${branchName}, ${title!}, ${state})`);\n if (includeOtherAuthors && isString(targetBranch)) {\n // do not use pr cache as it only fetches prs created by the bot account\n const pr = await helper.getPRByBranch(\n config.repository,\n targetBranch,\n branchName,\n );\n if (!pr) {\n return null;\n }\n\n return toRenovatePR(pr, null);\n }\n const prList = await platform.getPrList();\n const pr = prList.find(\n (p) =>\n p.sourceRepo === config.repository &&\n p.sourceBranch === branchName &&\n matchesState(p.state, state) &&\n (!title || p.title === title),\n );\n\n if (pr) {\n logger.debug(`Found PR #${pr.number}`);\n }\n return pr ?? null;\n },\n\n async createPr({\n sourceBranch,\n targetBranch,\n prTitle,\n prBody: rawBody,\n labels: labelNames,\n platformPrOptions,\n draftPR,\n }: CreatePRConfig): Promise<Pr> {\n let title = prTitle;\n const base = targetBranch;\n const head = sourceBranch;\n const body = sanitize(rawBody);\n if (draftPR) {\n title = DRAFT_PREFIX + title;\n }\n\n logger.debug(`Creating pull request: ${title} (${head} => ${base})`);\n try {\n const labels = Array.isArray(labelNames)\n ? await map(labelNames, lookupLabelByName)\n : [];\n const gpr = await helper.createPR(config.repository, {\n base,\n head,\n title,\n body,\n labels: labels.filter(isNumber),\n });\n\n if (platformPrOptions?.usePlatformAutomerge) {\n // Only Forgejo v10.0.0+ support delete_branch_after_merge.\n // This is required to not have undesired behavior when renovate finds existing branches on next run.\n // Codeberg usees git versioning like `11.0.1-99-c504062+gitea-1.22.0` so allow any version >= 10.0.0-0.\n if (semver.gte(defaults.version, '10.0.0-0')) {\n try {\n await helper.mergePR(config.repository, gpr.number, {\n Do:\n getMergeMethod(platformPrOptions?.automergeStrategy) ??\n config.mergeMethod,\n merge_when_checks_succeed: true,\n delete_branch_after_merge: true,\n });\n\n logger.debug(\n { prNumber: gpr.number },\n 'Forgejo-native automerge: success',\n );\n } catch (err) {\n logger.warn(\n { err, prNumber: gpr.number },\n 'Forgejo-native automerge: fail',\n );\n }\n } else {\n logger.debug(\n { prNumber: gpr.number },\n `Forgejo-native automerge: not supported on this version of Forgejo. Use 10.0.0 or newer.`,\n );\n }\n }\n\n const pr = toRenovatePR(gpr, botUserName);\n if (!pr) {\n throw new Error('Can not parse newly created Pull Request');\n }\n\n await ForgejoPrCache.setPr(\n forgejoHttp,\n config.repository,\n config.ignorePrAuthor,\n botUserName,\n pr,\n );\n return pr;\n } catch (err) {\n // When the user manually deletes a branch from Renovate, the PR remains but is no longer linked to any branch. In\n // the most recent versions of Forgejo, the PR gets automatically closed when that happens, but older versions do\n // not handle this properly and keep the PR open. As pushing a branch with the same name resurrects the PR, this\n // would cause a HTTP 409 conflict error, which we hereby gracefully handle.\n if (err.statusCode === 409) {\n logger.warn(\n { prTitle: title, sourceBranch },\n 'Attempting to gracefully recover from 409 Conflict response in createPr()',\n );\n\n // Refresh cached PR list and search for pull request with matching information\n ForgejoPrCache.forceSync();\n const pr = await platform.findPr({\n branchName: sourceBranch,\n state: 'open',\n });\n\n // If a valid PR was found, return and gracefully recover from the error. Otherwise, abort and throw error.\n // v8 ignore else -- TODO: add test #40625\n if (pr?.bodyStruct) {\n if (pr.title !== title || pr.bodyStruct.hash !== hashBody(body)) {\n logger.debug(\n `Recovered from 409 Conflict, but PR for ${sourceBranch} is outdated. Updating...`,\n );\n await platform.updatePr({\n number: pr.number,\n prTitle: title,\n prBody: body,\n });\n pr.title = title;\n pr.bodyStruct = getPrBodyStruct(body);\n } else {\n logger.debug(\n `Recovered from 409 Conflict and PR for ${sourceBranch} is up-to-date`,\n );\n }\n\n return pr;\n }\n }\n\n throw err;\n }\n },\n\n async updatePr({\n number,\n prTitle,\n prBody: body,\n labels,\n state,\n targetBranch,\n }: UpdatePrConfig): Promise<void> {\n let title = prTitle;\n if ((await getPrList()).find((pr) => pr.number === number)?.isDraft) {\n title = DRAFT_PREFIX + title;\n }\n\n const prUpdateParams: PRUpdateParams = {\n title,\n ...(body && { body }),\n ...(state && { state }),\n };\n if (targetBranch) {\n prUpdateParams.base = targetBranch;\n }\n\n /**\n * Update PR labels.\n * In the Forgejo API, labels are replaced on each update if the field is present.\n * If the field is not present (i.e., undefined), labels aren't updated.\n * However, the labels array must contain label IDs instead of names,\n * so a lookup is performed to fetch the details (including the ID) of each label.\n */\n if (Array.isArray(labels)) {\n prUpdateParams.labels = (await map(labels, lookupLabelByName)).filter(\n isNumber,\n );\n if (labels.length !== prUpdateParams.labels.length) {\n logger.warn(\n 'Some labels could not be looked up. Renovate may halt label updates assuming changes by others.',\n );\n }\n }\n\n const gpr = await helper.updatePR(\n config.repository,\n number,\n prUpdateParams,\n );\n const pr = toRenovatePR(gpr, botUserName);\n if (pr) {\n await ForgejoPrCache.setPr(\n forgejoHttp,\n config.repository,\n config.ignorePrAuthor,\n botUserName,\n pr,\n );\n }\n },\n\n async mergePr({ id, strategy }: MergePRConfig): Promise<boolean> {\n try {\n await helper.mergePR(config.repository, id, {\n Do: getMergeMethod(strategy) ?? config.mergeMethod,\n });\n return true;\n } catch (err) {\n logger.warn({ err, id }, 'Merging of PR failed');\n return false;\n }\n },\n\n getIssueList(): Promise<Issue[]> {\n if (config.hasIssuesEnabled === false) {\n return Promise.resolve([]);\n }\n config.issueList ??= helper\n .searchIssues(config.repository, { state: 'all' }, { memCache: false })\n .then((issues) => {\n const issueList = issues.map(toRenovateIssue);\n logger.debug(`Retrieved ${issueList.length} Issues`);\n return issueList;\n });\n\n return config.issueList;\n },\n\n async getIssue(number: number, memCache = true): Promise<Issue | null> {\n if (config.hasIssuesEnabled === false) {\n return null;\n }\n try {\n const body = (\n await helper.getIssue(config.repository, number, { memCache })\n ).body;\n return {\n number,\n body,\n };\n } catch (err) {\n logger.debug({ err, number }, 'Error getting issue');\n return null;\n }\n },\n\n async findIssue(title: string): Promise<Issue | null> {\n const issueList = await platform.getIssueList();\n const issue = issueList.find(\n (i) => i.state === 'open' && i.title === title,\n );\n\n if (!issue) {\n return null;\n }\n // TODO: types (#22198)\n logger.debug(`Found Issue #${issue.number!}`);\n // TODO #22198\n return getIssue!(issue.number!);\n },\n\n async ensureIssue({\n title,\n reuseTitle,\n body: content,\n labels: labelNames,\n shouldReOpen,\n once,\n }: EnsureIssueConfig): Promise<'updated' | 'created' | null> {\n logger.debug(`ensureIssue(${title})`);\n if (config.hasIssuesEnabled === false) {\n logger.info(\n 'Cannot ensure issue because issues are disabled in this repository',\n );\n return null;\n }\n try {\n const body = smartLinks(content);\n\n const issueList = await platform.getIssueList();\n let issues = issueList.filter((i) => i.title === title);\n if (!issues.length) {\n issues = issueList.filter((i) => i.title === reuseTitle);\n }\n\n const labels = Array.isArray(labelNames)\n ? (await Promise.all(labelNames.map(lookupLabelByName))).filter(\n isNumber,\n )\n : undefined;\n\n // Update any matching issues which currently exist\n if (issues.length) {\n let activeIssue = issues.find((i) => i.state === 'open');\n\n // If no active issue was found, decide if it shall be skipped, re-opened or updated without state change\n if (!activeIssue) {\n if (once) {\n logger.debug('Issue already closed - skipping update');\n return null;\n }\n if (shouldReOpen) {\n logger.debug('Reopening previously closed Issue');\n }\n\n // Pick the last issue in the list as the active one\n activeIssue = issues[issues.length - 1];\n }\n\n // Close any duplicate issues\n for (const issue of issues) {\n if (issue.state === 'open' && issue.number !== activeIssue.number) {\n // TODO: types (#22198)\n logger.warn({ issueNo: issue.number! }, 'Closing duplicate issue');\n // TODO #22198\n await helper.closeIssue(config.repository, issue.number!);\n }\n }\n\n // Check if issue has already correct state\n if (\n activeIssue.title === title &&\n activeIssue.body === body &&\n activeIssue.state === 'open'\n ) {\n logger.debug(\n // TODO: types (#22198)\n `Issue #${activeIssue.number!} is open and up to date - nothing to do`,\n );\n return null;\n }\n\n if (shouldReOpen || activeIssue.state === 'open') {\n // Update issue body and re-open\n logger.debug(`Updating Issue #${activeIssue.number}`);\n const existingIssue = await helper.updateIssue(\n config.repository,\n // TODO #22198\n activeIssue.number!,\n {\n body,\n title,\n state: 'open',\n },\n );\n\n // Test whether the issues need to be updated\n const existingLabelIds = (existingIssue.labels ?? []).map(\n (label) => label.id,\n );\n if (\n labels &&\n (labels.length !== existingLabelIds.length ||\n labels.filter((labelId) => !existingLabelIds.includes(labelId))\n .length !== 0)\n ) {\n await helper.updateIssueLabels(\n config.repository,\n // TODO #22198\n activeIssue.number!,\n {\n labels,\n },\n );\n }\n\n return 'updated';\n }\n }\n\n // Create new issue and reset cache\n const issue = await helper.createIssue(config.repository, {\n body,\n title,\n labels,\n });\n logger.debug(`Created new Issue #${issue.number}`);\n config.issueList = null;\n\n return 'created';\n } catch (err) {\n logger.warn({ err }, 'Could not ensure issue');\n }\n\n return null;\n },\n\n async ensureIssueClosing(title: string): Promise<void> {\n logger.debug(`ensureIssueClosing(${title})`);\n if (config.hasIssuesEnabled === false) {\n return;\n }\n const issueList = await platform.getIssueList();\n for (const issue of issueList) {\n if (issue.state === 'open' && issue.title === title) {\n logger.debug(`Closing issue...issueNo: ${issue.number!}`);\n // TODO #22198\n await helper.closeIssue(config.repository, issue.number!);\n }\n }\n },\n\n async deleteLabel(issue: number, labelName: string): Promise<void> {\n logger.debug(`Deleting label ${labelName} from Issue #${issue}`);\n const label = await lookupLabelByName(labelName);\n if (label) {\n await helper.unassignLabel(config.repository, issue, label);\n } else {\n logger.warn({ issue, labelName }, 'Failed to lookup label for deletion');\n }\n },\n\n async ensureComment({\n number: issue,\n topic,\n content,\n }: EnsureCommentConfig): Promise<boolean> {\n try {\n let body = sanitize(content);\n const commentList = await helper.getComments(config.repository, issue);\n\n // Search comment by either topic or exact body\n let comment: Comment | null = null;\n if (topic) {\n comment = findCommentByTopic(commentList, topic);\n body = `### ${topic}\\n\\n${body}`;\n } else {\n comment = findCommentByContent(commentList, body);\n }\n\n // Create a new comment if no match has been found, otherwise update if necessary\n if (!comment) {\n comment = await helper.createComment(config.repository, issue, body);\n logger.info(\n { repository: config.repository, issue, comment: comment.id },\n 'Comment added',\n );\n } else if (comment.body === body) {\n logger.debug(`Comment #${comment.id} is already up-to-date`);\n } else {\n await helper.updateComment(config.repository, comment.id, body);\n logger.debug(\n { repository: config.repository, issue, comment: comment.id },\n 'Comment updated',\n );\n }\n\n return true;\n } catch (err) {\n logger.warn({ err, issue, subject: topic }, 'Error ensuring comment');\n return false;\n }\n },\n\n async ensureCommentRemoval(\n deleteConfig: EnsureCommentRemovalConfig,\n ): Promise<void> {\n const { number: issue } = deleteConfig;\n const key =\n deleteConfig.type === 'by-topic'\n ? deleteConfig.topic\n : deleteConfig.content;\n logger.debug(`Ensuring comment \"${key}\" in #${issue} is removed`);\n const commentList = await helper.getComments(config.repository, issue);\n\n let comment: Comment | null = null;\n // v8 ignore else -- TODO: add test #40625\n if (deleteConfig.type === 'by-topic') {\n comment = findCommentByTopic(commentList, deleteConfig.topic);\n } else if (deleteConfig.type === 'by-content') {\n const body = sanitize(deleteConfig.content);\n comment = findCommentByContent(commentList, body);\n }\n\n // Abort and do nothing if no matching comment was found\n if (!comment) {\n return;\n }\n\n // Try to delete comment\n try {\n await helper.deleteComment(config.repository, comment.id);\n } catch (err) {\n logger.warn(\n { err, issue, config: deleteConfig },\n 'Error deleting comment',\n );\n }\n },\n\n async getBranchPr(branchName: string): Promise<Pr | null> {\n logger.debug(`getBranchPr(${branchName})`);\n const pr = await platform.findPr({ branchName, state: 'open' });\n return pr ? platform.getPr(pr.number) : null;\n },\n\n async addAssignees(number: number, assignees: string[]): Promise<void> {\n logger.debug(\n `Updating assignees '${assignees?.join(', ')}' on Issue #${number}`,\n );\n await helper.updateIssue(config.repository, number, {\n assignees,\n });\n },\n\n async addReviewers(number: number, reviewers: string[]): Promise<void> {\n logger.debug(`Adding reviewers '${reviewers?.join(', ')}' to #${number}`);\n try {\n const teamReviewers = new Set(\n reviewers\n .filter((r) => r.startsWith('team:'))\n .map((r) => r.substring(5)),\n );\n const userReviewers = new Set(\n reviewers.filter((r) => !r.startsWith('team:')),\n );\n\n await helper.requestPrReviewers(config.repository, number, {\n reviewers: [...userReviewers],\n ...(teamReviewers.size && {\n team_reviewers: [...teamReviewers],\n }),\n });\n } catch (err) {\n logger.warn({ err, number, reviewers }, 'Failed to assign reviewer');\n }\n },\n\n massageMarkdown(prBody: string): string {\n return smartTruncate(smartLinks(prBody), maxBodyLength());\n },\n\n maxBodyLength,\n};\n\nexport function maxBodyLength(): number {\n return 1000000;\n}\n\n/* oxlint-disable typescript/unbound-method */\nexport const {\n addAssignees,\n addReviewers,\n createPr,\n deleteLabel,\n ensureComment,\n ensureCommentRemoval,\n ensureIssue,\n ensureIssueClosing,\n findIssue,\n findPr,\n getBranchPr,\n getBranchStatus,\n getBranchStatusCheck,\n getIssue,\n getRawFile,\n getJsonFile,\n getIssueList,\n getPr,\n massageMarkdown,\n getPrList,\n getRepos,\n initPlatform,\n initRepo,\n mergePr,\n setBranchStatus,\n updatePr,\n} = platform;\n"],"mappings":"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"}
@@ -3,6 +3,7 @@ import { get, set } from "../../../util/cache/memory/index.js";
3
3
  import { logger } from "../../../logger/index.js";
4
4
  import { getQueryString, parseLinkHeader, parseUrl } from "../../../util/url.js";
5
5
  import { getCache } from "../../../util/cache/repository/index.js";
6
+ import { PRList } from "./schema.js";
6
7
  import { API_PATH, toRenovatePR } from "./utils.js";
7
8
  import { isNullOrUndefined } from "@sindresorhus/is";
8
9
  import { dequal } from "dequal";
@@ -88,10 +89,10 @@ var ForgejoPrCache = class ForgejoPrCache {
88
89
  ...this.ignorePrAuthor ? {} : { poster: this.author }
89
90
  });
90
91
  while (query) {
91
- const res = await http.getJsonUnchecked(`${API_PATH}/repos/${this.repo}/pulls?${query}`, {
92
+ const res = await http.getJson(`${API_PATH}/repos/${this.repo}/pulls?${query}`, {
92
93
  memCache: false,
93
94
  paginate: false
94
- });
95
+ }, PRList);
95
96
  if (!this.reconcile(res.body)) break;
96
97
  const uri = parseUrl(parseLinkHeader(res.headers.link)?.next?.url);
97
98
  query = uri ? uri.search : null;
@@ -1 +1 @@
1
- {"version":3,"file":"pr-cache.js","names":["memCache.get"],"sources":["../../../../lib/modules/platform/forgejo/pr-cache.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { TEMPORARY_ERROR } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { ForgejoHttp } from '../../../util/http/forgejo.ts';\nimport type { HttpResponse } from '../../../util/http/types.ts';\nimport {\n getQueryString,\n parseLinkHeader,\n parseUrl,\n} from '../../../util/url.ts';\nimport type { Pr } from '../types.ts';\nimport type { ForgejoPrCacheData, PR } from './types.ts';\nimport { API_PATH, toRenovatePR } from './utils.ts';\n\nexport class ForgejoPrCache {\n private cache: ForgejoPrCacheData;\n private items: Pr[] = [];\n private repo: string;\n private readonly ignorePrAuthor: boolean;\n private author: string | null;\n\n private constructor(\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ) {\n this.repo = repo;\n this.ignorePrAuthor = ignorePrAuthor;\n this.author = author;\n const repoCache = getCache();\n repoCache.platform ??= {};\n repoCache.platform.forgejo ??= {};\n let pullRequestCache = repoCache.platform.forgejo.pullRequestsCache as\n | ForgejoPrCacheData\n | undefined;\n if (\n isNullOrUndefined(pullRequestCache) ||\n pullRequestCache.author !== author\n ) {\n pullRequestCache = {\n items: {},\n updated_at: null,\n author,\n };\n }\n repoCache.platform.forgejo.pullRequestsCache = pullRequestCache;\n this.cache = pullRequestCache;\n this.updateItems();\n }\n\n static forceSync(): void {\n memCache.set('forgejo-pr-cache-synced', false);\n }\n\n private static async init(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ): Promise<ForgejoPrCache> {\n const res = new ForgejoPrCache(repo, ignorePrAuthor, author);\n const isSynced = memCache.get<true | undefined>('forgejo-pr-cache-synced');\n\n if (!isSynced) {\n await res.sync(http);\n memCache.set('forgejo-pr-cache-synced', true);\n }\n\n return res;\n }\n\n private getPrs(): Pr[] {\n return this.items;\n }\n\n static async getPrs(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n ): Promise<Pr[]> {\n const prCache = await ForgejoPrCache.init(\n http,\n repo,\n ignorePrAuthor,\n author,\n );\n return prCache.getPrs();\n }\n\n private setPr(item: Pr): void {\n this.cache.items[item.number] = item;\n this.updateItems();\n }\n\n static async setPr(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n item: Pr,\n ): Promise<void> {\n const prCache = await ForgejoPrCache.init(\n http,\n repo,\n ignorePrAuthor,\n author,\n );\n prCache.setPr(item);\n }\n\n private reconcile(rawItems: (PR | null)[]): boolean {\n const { items } = this.cache;\n let { updated_at } = this.cache;\n const cacheTime = updated_at ? DateTime.fromISO(updated_at) : null;\n\n let needNextPage = true;\n\n for (const rawItem of rawItems) {\n if (!rawItem) {\n logger.warn('Forgejo PR is empty, throwing temporary error');\n // Forgejo API sometimes returns empty PRs, so we throw a temporary error\n // https://github.com/go-forgejo/forgejo/blob/fcd096231ac2deaefbca10a7db1b9b01f1da93d7/services/convert/pull.go#L34-L52\n throw new Error(TEMPORARY_ERROR);\n }\n const id = rawItem.number;\n\n const newItem = toRenovatePR(rawItem, this.author);\n if (!newItem) {\n continue;\n }\n\n const oldItem = items[id];\n if (dequal(oldItem, newItem)) {\n needNextPage = false;\n continue;\n }\n\n items[id] = newItem;\n\n const itemTime = DateTime.fromISO(rawItem.updated_at);\n if (!cacheTime || itemTime > cacheTime) {\n updated_at = rawItem.updated_at;\n }\n }\n\n this.cache.updated_at = updated_at;\n\n return needNextPage;\n }\n\n private async sync(http: ForgejoHttp): Promise<ForgejoPrCache> {\n let query: string | null = getQueryString({\n state: 'all',\n sort: 'recentupdate',\n // Fetch 100 PRs on the first run to ensure we have the most recent PRs.\n // Forgejo will cap appropriate (50 by default, see `MAX_RESPONSE_ITEMS`).\n // https://docs.forgejo.com/administration/config-cheat-sheet#api-api\n // https://forgejo.org/docs/latest/admin/config-cheat-sheet/#api-api\n limit: this.items.length ? 20 : 100,\n // Supported since Forgejo v10.0.0.\n // Will be ignored by older instances.\n ...(this.ignorePrAuthor ? {} : { poster: this.author }),\n });\n\n while (query) {\n // TODO: use zod, typescript can't infer the type of the response #22198\n const res: HttpResponse<(PR | null)[]> = await http.getJsonUnchecked(\n `${API_PATH}/repos/${this.repo}/pulls?${query}`,\n {\n memCache: false,\n paginate: false,\n },\n );\n\n const needNextPage = this.reconcile(res.body);\n if (!needNextPage) {\n break;\n }\n\n const uri = parseUrl(parseLinkHeader(res.headers.link)?.next?.url);\n query = uri ? uri.search : null;\n }\n\n this.updateItems();\n\n return this;\n }\n\n /**\n * Ensure the pr cache starts with the most recent PRs.\n * JavaScript ensures that the cache is sorted by PR number.\n */\n private updateItems(): void {\n this.items = Object.values(this.cache.items).reverse();\n }\n}\n"],"mappings":";;;;;;;;;;AAkBA,IAAa,iBAAb,MAAa,eAAe;CAC1B;CACA,QAAsB,CAAC;CACvB;CACA;CACA;CAEA,YACE,MACA,gBACA,QACA;EACA,KAAK,OAAO;EACZ,KAAK,iBAAiB;EACtB,KAAK,SAAS;EACd,MAAM,YAAY,SAAS;EAC3B,UAAU,aAAa,CAAC;EACxB,UAAU,SAAS,YAAY,CAAC;EAChC,IAAI,mBAAmB,UAAU,SAAS,QAAQ;EAGlD,IACE,kBAAkB,gBAAgB,KAClC,iBAAiB,WAAW,QAE5B,mBAAmB;GACjB,OAAO,CAAC;GACR,YAAY;GACZ;EACF;EAEF,UAAU,SAAS,QAAQ,oBAAoB;EAC/C,KAAK,QAAQ;EACb,KAAK,YAAY;CACnB;CAEA,OAAO,YAAkB;EACvB,IAAa,2BAA2B,KAAK;CAC/C;CAEA,aAAqB,KACnB,MACA,MACA,gBACA,QACyB;EACzB,MAAM,MAAM,IAAI,eAAe,MAAM,gBAAgB,MAAM;EAG3D,IAAI,CAFaA,IAA+B,yBAEpC,GAAG;GACb,MAAM,IAAI,KAAK,IAAI;GACnB,IAAa,2BAA2B,IAAI;EAC9C;EAEA,OAAO;CACT;CAEA,SAAuB;EACrB,OAAO,KAAK;CACd;CAEA,aAAa,OACX,MACA,MACA,gBACA,QACe;EAOf,QAAO,MANe,eAAe,KACnC,MACA,MACA,gBACA,MACF,EAAA,CACe,OAAO;CACxB;CAEA,MAAc,MAAgB;EAC5B,KAAK,MAAM,MAAM,KAAK,UAAU;EAChC,KAAK,YAAY;CACnB;CAEA,aAAa,MACX,MACA,MACA,gBACA,QACA,MACe;EAOf,CAAA,MANsB,eAAe,KACnC,MACA,MACA,gBACA,MACF,EAAA,CACQ,MAAM,IAAI;CACpB;CAEA,UAAkB,UAAkC;EAClD,MAAM,EAAE,UAAU,KAAK;EACvB,IAAI,EAAE,eAAe,KAAK;EAC1B,MAAM,YAAY,aAAa,SAAS,QAAQ,UAAU,IAAI;EAE9D,IAAI,eAAe;EAEnB,KAAK,MAAM,WAAW,UAAU;GAC9B,IAAI,CAAC,SAAS;IACZ,OAAO,KAAK,+CAA+C;IAG3D,MAAM,IAAI,MAAM,eAAe;GACjC;GACA,MAAM,KAAK,QAAQ;GAEnB,MAAM,UAAU,aAAa,SAAS,KAAK,MAAM;GACjD,IAAI,CAAC,SACH;GAGF,MAAM,UAAU,MAAM;GACtB,IAAI,OAAO,SAAS,OAAO,GAAG;IAC5B,eAAe;IACf;GACF;GAEA,MAAM,MAAM;GAEZ,MAAM,WAAW,SAAS,QAAQ,QAAQ,UAAU;GACpD,IAAI,CAAC,aAAa,WAAW,WAC3B,aAAa,QAAQ;EAEzB;EAEA,KAAK,MAAM,aAAa;EAExB,OAAO;CACT;CAEA,MAAc,KAAK,MAA4C;EAC7D,IAAI,QAAuB,eAAe;GACxC,OAAO;GACP,MAAM;GAKN,OAAO,KAAK,MAAM,SAAS,KAAK;GAGhC,GAAI,KAAK,iBAAiB,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO;EACvD,CAAC;EAED,OAAO,OAAO;GAEZ,MAAM,MAAmC,MAAM,KAAK,iBAClD,GAAG,SAAS,SAAS,KAAK,KAAK,SAAS,SACxC;IACE,UAAU;IACV,UAAU;GACZ,CACF;GAGA,IAAI,CADiB,KAAK,UAAU,IAAI,IACxB,GACd;GAGF,MAAM,MAAM,SAAS,gBAAgB,IAAI,QAAQ,IAAI,CAAC,EAAE,MAAM,GAAG;GACjE,QAAQ,MAAM,IAAI,SAAS;EAC7B;EAEA,KAAK,YAAY;EAEjB,OAAO;CACT;;;;;CAMA,cAA4B;EAC1B,KAAK,QAAQ,OAAO,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC,QAAQ;CACvD;AACF"}
1
+ {"version":3,"file":"pr-cache.js","names":["memCache.get"],"sources":["../../../../lib/modules/platform/forgejo/pr-cache.ts"],"sourcesContent":["import { isNullOrUndefined } from '@sindresorhus/is';\nimport { dequal } from 'dequal';\nimport { DateTime } from 'luxon';\nimport { TEMPORARY_ERROR } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as memCache from '../../../util/cache/memory/index.ts';\nimport { getCache } from '../../../util/cache/repository/index.ts';\nimport type { ForgejoHttp } from '../../../util/http/forgejo.ts';\nimport {\n getQueryString,\n parseLinkHeader,\n parseUrl,\n} from '../../../util/url.ts';\nimport type { Pr } from '../types.ts';\nimport type { PR } from './schema.ts';\nimport { PRList } from './schema.ts';\nimport type { ForgejoPrCacheData } from './types.ts';\nimport { API_PATH, toRenovatePR } from './utils.ts';\n\nexport class ForgejoPrCache {\n private cache: ForgejoPrCacheData;\n private items: Pr[] = [];\n private repo: string;\n private readonly ignorePrAuthor: boolean;\n private author: string | null;\n\n private constructor(\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ) {\n this.repo = repo;\n this.ignorePrAuthor = ignorePrAuthor;\n this.author = author;\n const repoCache = getCache();\n repoCache.platform ??= {};\n repoCache.platform.forgejo ??= {};\n let pullRequestCache = repoCache.platform.forgejo.pullRequestsCache as\n | ForgejoPrCacheData\n | undefined;\n if (\n isNullOrUndefined(pullRequestCache) ||\n pullRequestCache.author !== author\n ) {\n pullRequestCache = {\n items: {},\n updated_at: null,\n author,\n };\n }\n repoCache.platform.forgejo.pullRequestsCache = pullRequestCache;\n this.cache = pullRequestCache;\n this.updateItems();\n }\n\n static forceSync(): void {\n memCache.set('forgejo-pr-cache-synced', false);\n }\n\n private static async init(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string | null,\n ): Promise<ForgejoPrCache> {\n const res = new ForgejoPrCache(repo, ignorePrAuthor, author);\n const isSynced = memCache.get<true | undefined>('forgejo-pr-cache-synced');\n\n if (!isSynced) {\n await res.sync(http);\n memCache.set('forgejo-pr-cache-synced', true);\n }\n\n return res;\n }\n\n private getPrs(): Pr[] {\n return this.items;\n }\n\n static async getPrs(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n ): Promise<Pr[]> {\n const prCache = await ForgejoPrCache.init(\n http,\n repo,\n ignorePrAuthor,\n author,\n );\n return prCache.getPrs();\n }\n\n private setPr(item: Pr): void {\n this.cache.items[item.number] = item;\n this.updateItems();\n }\n\n static async setPr(\n http: ForgejoHttp,\n repo: string,\n ignorePrAuthor: boolean,\n author: string,\n item: Pr,\n ): Promise<void> {\n const prCache = await ForgejoPrCache.init(\n http,\n repo,\n ignorePrAuthor,\n author,\n );\n prCache.setPr(item);\n }\n\n private reconcile(rawItems: (PR | null)[]): boolean {\n const { items } = this.cache;\n let { updated_at } = this.cache;\n const cacheTime = updated_at ? DateTime.fromISO(updated_at) : null;\n\n let needNextPage = true;\n\n for (const rawItem of rawItems) {\n if (!rawItem) {\n logger.warn('Forgejo PR is empty, throwing temporary error');\n // Forgejo API sometimes returns empty PRs, so we throw a temporary error\n // https://github.com/go-forgejo/forgejo/blob/fcd096231ac2deaefbca10a7db1b9b01f1da93d7/services/convert/pull.go#L34-L52\n throw new Error(TEMPORARY_ERROR);\n }\n const id = rawItem.number;\n\n const newItem = toRenovatePR(rawItem, this.author);\n if (!newItem) {\n continue;\n }\n\n const oldItem = items[id];\n if (dequal(oldItem, newItem)) {\n needNextPage = false;\n continue;\n }\n\n items[id] = newItem;\n\n const itemTime = DateTime.fromISO(rawItem.updated_at);\n if (!cacheTime || itemTime > cacheTime) {\n updated_at = rawItem.updated_at;\n }\n }\n\n this.cache.updated_at = updated_at;\n\n return needNextPage;\n }\n\n private async sync(http: ForgejoHttp): Promise<ForgejoPrCache> {\n let query: string | null = getQueryString({\n state: 'all',\n sort: 'recentupdate',\n // Fetch 100 PRs on the first run to ensure we have the most recent PRs.\n // Forgejo will cap appropriate (50 by default, see `MAX_RESPONSE_ITEMS`).\n // https://docs.forgejo.com/administration/config-cheat-sheet#api-api\n // https://forgejo.org/docs/latest/admin/config-cheat-sheet/#api-api\n limit: this.items.length ? 20 : 100,\n // Supported since Forgejo v10.0.0.\n // Will be ignored by older instances.\n ...(this.ignorePrAuthor ? {} : { poster: this.author }),\n });\n\n while (query) {\n const res = await http.getJson(\n `${API_PATH}/repos/${this.repo}/pulls?${query}`,\n {\n memCache: false,\n paginate: false,\n },\n PRList,\n );\n\n const needNextPage = this.reconcile(res.body);\n if (!needNextPage) {\n break;\n }\n\n const uri = parseUrl(parseLinkHeader(res.headers.link)?.next?.url);\n query = uri ? uri.search : null;\n }\n\n this.updateItems();\n\n return this;\n }\n\n /**\n * Ensure the pr cache starts with the most recent PRs.\n * JavaScript ensures that the cache is sorted by PR number.\n */\n private updateItems(): void {\n this.items = Object.values(this.cache.items).reverse();\n }\n}\n"],"mappings":";;;;;;;;;;;AAmBA,IAAa,iBAAb,MAAa,eAAe;CAC1B;CACA,QAAsB,CAAC;CACvB;CACA;CACA;CAEA,YACE,MACA,gBACA,QACA;EACA,KAAK,OAAO;EACZ,KAAK,iBAAiB;EACtB,KAAK,SAAS;EACd,MAAM,YAAY,SAAS;EAC3B,UAAU,aAAa,CAAC;EACxB,UAAU,SAAS,YAAY,CAAC;EAChC,IAAI,mBAAmB,UAAU,SAAS,QAAQ;EAGlD,IACE,kBAAkB,gBAAgB,KAClC,iBAAiB,WAAW,QAE5B,mBAAmB;GACjB,OAAO,CAAC;GACR,YAAY;GACZ;EACF;EAEF,UAAU,SAAS,QAAQ,oBAAoB;EAC/C,KAAK,QAAQ;EACb,KAAK,YAAY;CACnB;CAEA,OAAO,YAAkB;EACvB,IAAa,2BAA2B,KAAK;CAC/C;CAEA,aAAqB,KACnB,MACA,MACA,gBACA,QACyB;EACzB,MAAM,MAAM,IAAI,eAAe,MAAM,gBAAgB,MAAM;EAG3D,IAAI,CAFaA,IAA+B,yBAEpC,GAAG;GACb,MAAM,IAAI,KAAK,IAAI;GACnB,IAAa,2BAA2B,IAAI;EAC9C;EAEA,OAAO;CACT;CAEA,SAAuB;EACrB,OAAO,KAAK;CACd;CAEA,aAAa,OACX,MACA,MACA,gBACA,QACe;EAOf,QAAO,MANe,eAAe,KACnC,MACA,MACA,gBACA,MACF,EAAA,CACe,OAAO;CACxB;CAEA,MAAc,MAAgB;EAC5B,KAAK,MAAM,MAAM,KAAK,UAAU;EAChC,KAAK,YAAY;CACnB;CAEA,aAAa,MACX,MACA,MACA,gBACA,QACA,MACe;EAOf,CAAA,MANsB,eAAe,KACnC,MACA,MACA,gBACA,MACF,EAAA,CACQ,MAAM,IAAI;CACpB;CAEA,UAAkB,UAAkC;EAClD,MAAM,EAAE,UAAU,KAAK;EACvB,IAAI,EAAE,eAAe,KAAK;EAC1B,MAAM,YAAY,aAAa,SAAS,QAAQ,UAAU,IAAI;EAE9D,IAAI,eAAe;EAEnB,KAAK,MAAM,WAAW,UAAU;GAC9B,IAAI,CAAC,SAAS;IACZ,OAAO,KAAK,+CAA+C;IAG3D,MAAM,IAAI,MAAM,eAAe;GACjC;GACA,MAAM,KAAK,QAAQ;GAEnB,MAAM,UAAU,aAAa,SAAS,KAAK,MAAM;GACjD,IAAI,CAAC,SACH;GAGF,MAAM,UAAU,MAAM;GACtB,IAAI,OAAO,SAAS,OAAO,GAAG;IAC5B,eAAe;IACf;GACF;GAEA,MAAM,MAAM;GAEZ,MAAM,WAAW,SAAS,QAAQ,QAAQ,UAAU;GACpD,IAAI,CAAC,aAAa,WAAW,WAC3B,aAAa,QAAQ;EAEzB;EAEA,KAAK,MAAM,aAAa;EAExB,OAAO;CACT;CAEA,MAAc,KAAK,MAA4C;EAC7D,IAAI,QAAuB,eAAe;GACxC,OAAO;GACP,MAAM;GAKN,OAAO,KAAK,MAAM,SAAS,KAAK;GAGhC,GAAI,KAAK,iBAAiB,CAAC,IAAI,EAAE,QAAQ,KAAK,OAAO;EACvD,CAAC;EAED,OAAO,OAAO;GACZ,MAAM,MAAM,MAAM,KAAK,QACrB,GAAG,SAAS,SAAS,KAAK,KAAK,SAAS,SACxC;IACE,UAAU;IACV,UAAU;GACZ,GACA,MACF;GAGA,IAAI,CADiB,KAAK,UAAU,IAAI,IACxB,GACd;GAGF,MAAM,MAAM,SAAS,gBAAgB,IAAI,QAAQ,IAAI,CAAC,EAAE,MAAM,GAAG;GACjE,QAAQ,MAAM,IAAI,SAAS;EAC7B;EAEA,KAAK,YAAY;EAEjB,OAAO;CACT;;;;;CAMA,cAA4B;EAC1B,KAAK,QAAQ,OAAO,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC,QAAQ;CACvD;AACF"}
@@ -0,0 +1,148 @@
1
+ import { fromBase64 } from "../../../util/string.js";
2
+ import { DeepNullish, EmailAddress, LooseArray } from "../../../util/schema-utils/index.js";
3
+ import { LongCommitSha } from "../../../util/schema-utils/git.js";
4
+ import { z } from "zod/v4";
5
+ //#region lib/modules/platform/forgejo/schema.ts
6
+ const ContentsCommon = z.object({
7
+ name: z.string(),
8
+ path: z.string()
9
+ });
10
+ const ContentsFile = ContentsCommon.extend({
11
+ type: z.literal("file"),
12
+ content: z.string().nullable()
13
+ }).transform((input) => ({
14
+ ...input,
15
+ contentString: input.content ? fromBase64(input.content) : ""
16
+ }));
17
+ const ContentsDir = ContentsCommon.extend({ type: z.literal("dir") });
18
+ const ContentsSymlink = ContentsCommon.extend({ type: z.literal("symlink") });
19
+ const ContentsSubmodule = ContentsCommon.extend({ type: z.literal("submodule") });
20
+ const RepoContents = z.discriminatedUnion("type", [
21
+ ContentsFile,
22
+ ContentsDir,
23
+ ContentsSymlink,
24
+ ContentsSubmodule
25
+ ]);
26
+ const ContentsListResponse = z.array(RepoContents);
27
+ const User = DeepNullish(z.object({
28
+ id: z.number(),
29
+ email: EmailAddress.optional(),
30
+ full_name: z.string().optional(),
31
+ login: z.string()
32
+ }));
33
+ const RepoPermission = z.object({
34
+ admin: z.boolean(),
35
+ pull: z.boolean(),
36
+ push: z.boolean()
37
+ });
38
+ const PRMergeMethod = z.enum([
39
+ "fast-forward-only",
40
+ "merge",
41
+ "rebase",
42
+ "rebase-merge",
43
+ "squash"
44
+ ]);
45
+ const Repo = DeepNullish(z.object({
46
+ id: z.number(),
47
+ allow_fast_forward_only_merge: z.boolean().default(false),
48
+ allow_merge_commits: z.boolean().default(false),
49
+ allow_rebase: z.boolean().default(false),
50
+ allow_rebase_explicit: z.boolean().default(false),
51
+ allow_squash_merge: z.boolean().default(false),
52
+ archived: z.boolean().optional(),
53
+ clone_url: z.string().optional(),
54
+ default_merge_style: PRMergeMethod.optional().catch(void 0),
55
+ external_tracker: z.unknown().optional(),
56
+ has_issues: z.boolean().optional().default(false),
57
+ has_pull_requests: z.boolean().optional(),
58
+ ssh_url: z.string().optional(),
59
+ default_branch: z.string(),
60
+ empty: z.boolean().optional(),
61
+ fork: z.boolean().optional(),
62
+ full_name: z.string(),
63
+ mirror: z.boolean().optional(),
64
+ owner: User,
65
+ permissions: RepoPermission
66
+ }));
67
+ const Label = DeepNullish(z.object({
68
+ id: z.number(),
69
+ name: z.string(),
70
+ description: z.string().optional(),
71
+ color: z.string().optional()
72
+ }));
73
+ const PRState = z.enum([
74
+ "open",
75
+ "closed",
76
+ "all"
77
+ ]);
78
+ const IssueState = z.enum([
79
+ "open",
80
+ "closed",
81
+ "all"
82
+ ]);
83
+ const PartialRepo = z.object({ full_name: z.string() });
84
+ const PR = DeepNullish(z.object({
85
+ number: z.number(),
86
+ state: PRState,
87
+ title: z.string(),
88
+ body: z.string(),
89
+ mergeable: z.boolean(),
90
+ merged: z.boolean().optional(),
91
+ created_at: z.string(),
92
+ updated_at: z.string(),
93
+ closed_at: z.string().optional(),
94
+ diff_url: z.string().optional(),
95
+ base: z.object({ ref: z.string() }).optional(),
96
+ head: z.object({
97
+ label: z.string(),
98
+ sha: LongCommitSha,
99
+ repo: PartialRepo.optional()
100
+ }).optional(),
101
+ assignee: User.optional(),
102
+ assignees: z.array(User).optional(),
103
+ user: User.optional(),
104
+ labels: z.array(Label).optional()
105
+ }));
106
+ const PRList = LooseArray(PR.nullable());
107
+ const Issue = DeepNullish(z.object({
108
+ number: z.number(),
109
+ state: IssueState.optional(),
110
+ title: z.string(),
111
+ body: z.string(),
112
+ assignees: z.array(User).optional(),
113
+ labels: z.array(Label).optional()
114
+ }));
115
+ const Comment = z.object({
116
+ id: z.number(),
117
+ body: z.string()
118
+ });
119
+ const CommitStatusType = z.enum([
120
+ "pending",
121
+ "success",
122
+ "error",
123
+ "failure",
124
+ "warning",
125
+ "unknown"
126
+ ]).catch("unknown");
127
+ const CommitStatus = DeepNullish(z.object({
128
+ id: z.number(),
129
+ status: CommitStatusType,
130
+ context: z.string(),
131
+ description: z.string().optional(),
132
+ target_url: z.string().optional(),
133
+ created_at: z.string()
134
+ }));
135
+ const Commit = z.object({ id: z.string() });
136
+ z.object({
137
+ name: z.string(),
138
+ commit: Commit
139
+ });
140
+ const RepoSearchResults = z.object({
141
+ ok: z.boolean(),
142
+ data: z.array(Repo)
143
+ });
144
+ const Version = z.object({ version: z.string() });
145
+ //#endregion
146
+ export { Comment, CommitStatus, ContentsListResponse, Issue, Label, PR, PRList, Repo, RepoContents, RepoSearchResults, User, Version };
147
+
148
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../../../lib/modules/platform/forgejo/schema.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport { LongCommitSha } from '../../../util/schema-utils/git.ts';\nimport {\n DeepNullish,\n EmailAddress,\n LooseArray,\n} from '../../../util/schema-utils/index.ts';\nimport { fromBase64 } from '../../../util/string.ts';\n\nconst ContentsCommon = z.object({\n name: z.string(),\n path: z.string(),\n});\n\nconst ContentsFile = ContentsCommon.extend({\n type: z.literal('file'),\n content: z.string().nullable(),\n}).transform((input) => ({\n ...input,\n contentString: input.content ? fromBase64(input.content) : '',\n}));\n\nconst ContentsDir = ContentsCommon.extend({ type: z.literal('dir') });\nconst ContentsSymlink = ContentsCommon.extend({ type: z.literal('symlink') });\nconst ContentsSubmodule = ContentsCommon.extend({\n type: z.literal('submodule'),\n});\n\nexport const RepoContents = z.discriminatedUnion('type', [\n ContentsFile,\n ContentsDir,\n ContentsSymlink,\n ContentsSubmodule,\n]);\nexport type RepoContents = z.infer<typeof RepoContents>;\n\nexport const ContentsListResponse = z.array(RepoContents);\n\nexport const User = DeepNullish(\n z.object({\n id: z.number(),\n email: EmailAddress.optional(),\n full_name: z.string().optional(),\n login: z.string(),\n }),\n);\nexport type User = z.infer<typeof User>;\n\nexport const RepoPermission = z.object({\n admin: z.boolean(),\n pull: z.boolean(),\n push: z.boolean(),\n});\nexport type RepoPermission = z.infer<typeof RepoPermission>;\n\nexport const PRMergeMethod = z.enum([\n 'fast-forward-only',\n 'merge',\n 'rebase',\n 'rebase-merge',\n 'squash',\n]);\nexport type PRMergeMethod = z.infer<typeof PRMergeMethod>;\n\n// Lenient Repo schema - only validates fields Renovate reads, most are optional\nexport const Repo = DeepNullish(\n z.object({\n id: z.number(),\n allow_fast_forward_only_merge: z.boolean().default(false),\n allow_merge_commits: z.boolean().default(false),\n allow_rebase: z.boolean().default(false),\n allow_rebase_explicit: z.boolean().default(false),\n allow_squash_merge: z.boolean().default(false),\n archived: z.boolean().optional(),\n clone_url: z.string().optional(),\n // catch unknown merge methods e.g. `manually-merged`\n default_merge_style: PRMergeMethod.optional().catch(undefined),\n external_tracker: z.unknown().optional(),\n has_issues: z.boolean().optional().default(false),\n has_pull_requests: z.boolean().optional(),\n ssh_url: z.string().optional(),\n default_branch: z.string(),\n empty: z.boolean().optional(),\n fork: z.boolean().optional(),\n full_name: z.string(),\n mirror: z.boolean().optional(),\n owner: User,\n permissions: RepoPermission,\n }),\n);\nexport type Repo = z.infer<typeof Repo>;\n\nexport const Label = DeepNullish(\n z.object({\n id: z.number(),\n name: z.string(),\n description: z.string().optional(),\n color: z.string().optional(),\n }),\n);\nexport type Label = z.infer<typeof Label>;\n\nexport const PRState = z.enum(['open', 'closed', 'all']);\nexport type PRState = z.infer<typeof PRState>;\n\nexport const IssueState = z.enum(['open', 'closed', 'all']);\nexport type IssueState = z.infer<typeof IssueState>;\n\n// Lenient partial repo schema for embedded repo references in PRs (only full_name is read)\nconst PartialRepo = z.object({\n full_name: z.string(),\n});\n\nexport const PR = DeepNullish(\n z.object({\n number: z.number(),\n state: PRState,\n title: z.string(),\n body: z.string(),\n mergeable: z.boolean(),\n merged: z.boolean().optional(),\n created_at: z.string(),\n updated_at: z.string(),\n closed_at: z.string().optional(),\n diff_url: z.string().optional(),\n base: z\n .object({\n ref: z.string(),\n })\n .optional(),\n head: z\n .object({\n label: z.string(),\n sha: LongCommitSha,\n repo: PartialRepo.optional(),\n })\n .optional(),\n assignee: User.optional(),\n assignees: z.array(User).optional(),\n user: User.optional(),\n labels: z.array(Label).optional(),\n }),\n);\nexport type PR = z.infer<typeof PR>;\n\n// TODO remove when the TEMPORARY_ERROR in pr-cache.ts is no longer needed\nexport const NullablePR = PR.nullable();\n\nexport const PRList = LooseArray(NullablePR);\n\nexport const Issue = DeepNullish(\n z.object({\n number: z.number(),\n state: IssueState.optional(),\n title: z.string(),\n body: z.string(),\n assignees: z.array(User).optional(),\n labels: z.array(Label).optional(),\n }),\n);\nexport type Issue = z.infer<typeof Issue>;\n\nexport const Comment = z.object({\n id: z.number(),\n body: z.string(),\n});\nexport type Comment = z.infer<typeof Comment>;\n\nexport const CommitStatusType = z\n .enum(['pending', 'success', 'error', 'failure', 'warning', 'unknown'])\n .catch('unknown');\nexport type CommitStatusType = z.infer<typeof CommitStatusType>;\n\nexport const CommitStatus = DeepNullish(\n z.object({\n id: z.number(),\n status: CommitStatusType,\n context: z.string(),\n description: z.string().optional(),\n target_url: z.string().optional(),\n created_at: z.string(),\n }),\n);\nexport type CommitStatus = z.infer<typeof CommitStatus>;\n\nexport const Commit = z.object({\n id: z.string(),\n});\nexport type Commit = z.infer<typeof Commit>;\n\nexport const Branch = z.object({\n name: z.string(),\n commit: Commit,\n});\nexport type Branch = z.infer<typeof Branch>;\n\nexport const RepoSearchResults = z.object({\n ok: z.boolean(),\n data: z.array(Repo),\n});\n\nexport const Version = z.object({\n version: z.string(),\n});\n"],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import { CONFIG_GIT_URL_UNAVAILABLE, REPOSITORY_BLOCKED } from "../../../constants/error-messages.js";
1
+ import { CONFIG_GIT_URL_UNAVAILABLE } from "../../../constants/error-messages.js";
2
2
  import { regEx } from "../../../util/regex.js";
3
3
  import { logger } from "../../../logger/index.js";
4
4
  import { parseUrl } from "../../../util/url.js";
5
5
  import { find } from "../../../util/host-rules.js";
6
+ import { coerceArray } from "../../../util/array.js";
6
7
  import { getPrBodyStruct } from "../pr-body.js";
7
8
  import { isNonEmptyArray } from "@sindresorhus/is";
8
9
  //#region lib/modules/platform/forgejo/utils.ts
@@ -50,7 +51,6 @@ const API_PATH = "/api/v1";
50
51
  const DRAFT_PREFIX = "WIP: ";
51
52
  const reconfigurePrRegex = regEx(/reconfigure$/g);
52
53
  function toRenovatePR(data, author) {
53
- if (!data) return null;
54
54
  if (!data.base?.ref || !data.head?.label || !data.head?.sha || !data.head?.repo?.full_name) {
55
55
  logger.trace(`Skipping Pull Request #${data.number} due to missing base and/or head branch`);
56
56
  return null;
@@ -64,7 +64,7 @@ function toRenovatePR(data, author) {
64
64
  isDraft = true;
65
65
  }
66
66
  return {
67
- labels: (data?.labels ?? []).map((l) => l.name),
67
+ labels: coerceArray(data.labels).map((l) => l.name),
68
68
  number: data.number,
69
69
  state: data.merged ? "merged" : data.state,
70
70
  title,
@@ -108,8 +108,6 @@ function isAllowed(style, repo) {
108
108
  case "squash": return repo.allow_squash_merge;
109
109
  case "fast-forward-only": return repo.allow_fast_forward_only_merge;
110
110
  }
111
- logger.debug("Repo has unknown merge style - aborting renovation");
112
- throw new Error(REPOSITORY_BLOCKED);
113
111
  }
114
112
  //#endregion
115
113
  export { API_PATH, DRAFT_PREFIX, getMergeMethod, getRepoUrl, isAllowed, smartLinks, toRenovatePR, trimTrailingApiPath, usableRepo };
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":["hostRules.find"],"sources":["../../../../lib/modules/platform/forgejo/utils.ts"],"sourcesContent":["import { isNonEmptyArray } from '@sindresorhus/is';\nimport type { MergeStrategy } from '../../../config/types.ts';\nimport {\n CONFIG_GIT_URL_UNAVAILABLE,\n REPOSITORY_BLOCKED,\n} from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport * as hostRules from '../../../util/host-rules.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { parseUrl } from '../../../util/url.ts';\nimport { getPrBodyStruct } from '../pr-body.ts';\nimport type { GitUrlOption, Pr } from '../types.ts';\nimport type { PR, PRMergeMethod, Repo } from './types.ts';\n\nexport function smartLinks(body: string): string {\n return body\n ?.replace(regEx(/\\]\\(\\.\\.\\/issues\\//g), '](issues/')\n .replace(regEx(/\\]\\(\\.\\.\\/pull\\//g), '](pulls/');\n}\n\nexport function trimTrailingApiPath(url: string): string {\n return url?.replace(regEx(/api\\/v1\\/?$/g), '');\n}\n\nexport function getRepoUrl(\n repo: Repo,\n gitUrl: GitUrlOption | undefined,\n endpoint: string,\n): string {\n if (gitUrl === 'ssh') {\n if (!repo.ssh_url) {\n throw new Error(CONFIG_GIT_URL_UNAVAILABLE);\n }\n logger.debug(`Using SSH URL: ${repo.ssh_url}`);\n return repo.ssh_url;\n }\n\n // Find options for current host and determine Git endpoint\n const opts = hostRules.find({\n hostType: 'forgejo',\n url: endpoint,\n });\n\n if (gitUrl === 'endpoint') {\n const url = parseUrl(endpoint);\n if (!url) {\n throw new Error(CONFIG_GIT_URL_UNAVAILABLE);\n }\n url.username = opts.token ?? '';\n url.pathname = `${url.pathname}${repo.full_name}.git`;\n logger.debug(\n { url: url.toString() },\n 'using URL based on configured endpoint',\n );\n return url.toString();\n }\n\n if (!repo.clone_url) {\n throw new Error(CONFIG_GIT_URL_UNAVAILABLE);\n }\n\n logger.debug(`Using HTTP URL: ${repo.clone_url}`);\n const repoUrl = parseUrl(repo.clone_url);\n if (!repoUrl) {\n throw new Error(CONFIG_GIT_URL_UNAVAILABLE);\n }\n repoUrl.username = opts.token ?? '';\n return repoUrl.toString();\n}\n\nexport function getMergeMethod(\n strategy: MergeStrategy | undefined,\n): PRMergeMethod | null {\n switch (strategy) {\n case 'fast-forward':\n return 'rebase';\n case 'merge-commit':\n return 'merge';\n case 'rebase':\n return 'rebase-merge';\n case 'squash':\n return strategy;\n case 'auto':\n default:\n return null;\n }\n}\n\nexport const API_PATH = '/api/v1';\n\nexport const DRAFT_PREFIX = 'WIP: ';\nconst reconfigurePrRegex = regEx(/reconfigure$/g);\n\nexport function toRenovatePR(data: PR, author: string | null): Pr | null {\n if (!data) {\n return null;\n }\n\n if (\n !data.base?.ref ||\n !data.head?.label ||\n !data.head?.sha ||\n !data.head?.repo?.full_name\n ) {\n logger.trace(\n `Skipping Pull Request #${data.number} due to missing base and/or head branch`,\n );\n return null;\n }\n\n const createdBy = data.user?.login;\n if (\n createdBy &&\n author &&\n !reconfigurePrRegex.test(data.head.label) &&\n createdBy !== author\n ) {\n return null;\n }\n\n let title = data.title;\n let isDraft = false;\n if (title.startsWith(DRAFT_PREFIX)) {\n title = title.substring(DRAFT_PREFIX.length);\n isDraft = true;\n }\n const labels = (data?.labels ?? []).map((l) => l.name);\n\n return {\n labels,\n number: data.number,\n state: data.merged ? 'merged' : data.state,\n title,\n isDraft,\n bodyStruct: getPrBodyStruct(data.body),\n sha: data.head.sha,\n sourceBranch: data.head.label,\n targetBranch: data.base.ref,\n sourceRepo: data.head.repo.full_name,\n createdAt: data.created_at,\n cannotMergeReason: data.mergeable\n ? undefined\n : `pr.mergeable=\"${data.mergeable}\"`,\n hasAssignees: !!(data.assignee?.login ?? isNonEmptyArray(data.assignees)),\n };\n}\n\n/**\n * Check if a repository is usable.\n * A repo isn't usable if one of the following conditions is met:\n * - The repo is a `mirror`\n * - We don't have pull or push permissions\n * - Pull requests are disabled\n * @param repo Repo to check\n * @returns `true` if the repository is usable, `false` otherwise\n */\nexport function usableRepo(repo: Repo): boolean {\n if (repo.mirror === true) {\n return false;\n }\n\n if (repo.permissions.pull === false || repo.permissions.push === false) {\n logger.debug(\n `Skipping repository ${repo.full_name} because of missing pull or push permissions`,\n );\n return false;\n }\n\n if (repo.has_pull_requests === false) {\n logger.debug(\n `Skipping repository ${repo.full_name} because pull requests are disabled`,\n );\n return false;\n }\n return true;\n}\n\nexport function isAllowed(style: PRMergeMethod, repo: Repo): boolean {\n switch (style) {\n case 'merge':\n return repo.allow_merge_commits;\n case 'rebase':\n return repo.allow_rebase;\n case 'rebase-merge':\n return repo.allow_rebase_explicit;\n case 'squash':\n return repo.allow_squash_merge;\n case 'fast-forward-only':\n return repo.allow_fast_forward_only_merge;\n }\n logger.debug('Repo has unknown merge style - aborting renovation');\n throw new Error(REPOSITORY_BLOCKED);\n}\n"],"mappings":";;;;;;;;AAcA,SAAgB,WAAW,MAAsB;CAC/C,OAAO,MACH,QAAQ,MAAM,qBAAqB,GAAG,WAAW,CAAC,CACnD,QAAQ,MAAM,mBAAmB,GAAG,UAAU;AACnD;AAEA,SAAgB,oBAAoB,KAAqB;CACvD,OAAO,KAAK,QAAQ,MAAM,cAAc,GAAG,EAAE;AAC/C;AAEA,SAAgB,WACd,MACA,QACA,UACQ;CACR,IAAI,WAAW,OAAO;EACpB,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,MAAM,0BAA0B;EAE5C,OAAO,MAAM,kBAAkB,KAAK,SAAS;EAC7C,OAAO,KAAK;CACd;CAGA,MAAM,OAAOA,KAAe;EAC1B,UAAU;EACV,KAAK;CACP,CAAC;CAED,IAAI,WAAW,YAAY;EACzB,MAAM,MAAM,SAAS,QAAQ;EAC7B,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,0BAA0B;EAE5C,IAAI,WAAW,KAAK,SAAS;EAC7B,IAAI,WAAW,GAAG,IAAI,WAAW,KAAK,UAAU;EAChD,OAAO,MACL,EAAE,KAAK,IAAI,SAAS,EAAE,GACtB,wCACF;EACA,OAAO,IAAI,SAAS;CACtB;CAEA,IAAI,CAAC,KAAK,WACR,MAAM,IAAI,MAAM,0BAA0B;CAG5C,OAAO,MAAM,mBAAmB,KAAK,WAAW;CAChD,MAAM,UAAU,SAAS,KAAK,SAAS;CACvC,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,0BAA0B;CAE5C,QAAQ,WAAW,KAAK,SAAS;CACjC,OAAO,QAAQ,SAAS;AAC1B;AAEA,SAAgB,eACd,UACsB;CACtB,QAAQ,UAAR;EACE,KAAK,gBACH,OAAO;EACT,KAAK,gBACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,UACH,OAAO;EAET,SACE,OAAO;CACX;AACF;AAEA,MAAa,WAAW;AAExB,MAAa,eAAe;AAC5B,MAAM,qBAAqB,MAAM,eAAe;AAEhD,SAAgB,aAAa,MAAU,QAAkC;CACvE,IAAI,CAAC,MACH,OAAO;CAGT,IACE,CAAC,KAAK,MAAM,OACZ,CAAC,KAAK,MAAM,SACZ,CAAC,KAAK,MAAM,OACZ,CAAC,KAAK,MAAM,MAAM,WAClB;EACA,OAAO,MACL,0BAA0B,KAAK,OAAO,wCACxC;EACA,OAAO;CACT;CAEA,MAAM,YAAY,KAAK,MAAM;CAC7B,IACE,aACA,UACA,CAAC,mBAAmB,KAAK,KAAK,KAAK,KAAK,KACxC,cAAc,QAEd,OAAO;CAGT,IAAI,QAAQ,KAAK;CACjB,IAAI,UAAU;CACd,IAAI,MAAM,WAAA,OAAuB,GAAG;EAClC,QAAQ,MAAM,UAAU,CAAmB;EAC3C,UAAU;CACZ;CAGA,OAAO;EACL,SAHc,MAAM,UAAU,CAAC,EAAA,CAAG,KAAK,MAAM,EAAE,IAG1C;EACL,QAAQ,KAAK;EACb,OAAO,KAAK,SAAS,WAAW,KAAK;EACrC;EACA;EACA,YAAY,gBAAgB,KAAK,IAAI;EACrC,KAAK,KAAK,KAAK;EACf,cAAc,KAAK,KAAK;EACxB,cAAc,KAAK,KAAK;EACxB,YAAY,KAAK,KAAK,KAAK;EAC3B,WAAW,KAAK;EAChB,mBAAmB,KAAK,YACpB,KAAA,IACA,iBAAiB,KAAK,UAAU;EACpC,cAAc,CAAC,EAAE,KAAK,UAAU,SAAS,gBAAgB,KAAK,SAAS;CACzE;AACF;;;;;;;;;;AAWA,SAAgB,WAAW,MAAqB;CAC9C,IAAI,KAAK,WAAW,MAClB,OAAO;CAGT,IAAI,KAAK,YAAY,SAAS,SAAS,KAAK,YAAY,SAAS,OAAO;EACtE,OAAO,MACL,uBAAuB,KAAK,UAAU,6CACxC;EACA,OAAO;CACT;CAEA,IAAI,KAAK,sBAAsB,OAAO;EACpC,OAAO,MACL,uBAAuB,KAAK,UAAU,oCACxC;EACA,OAAO;CACT;CACA,OAAO;AACT;AAEA,SAAgB,UAAU,OAAsB,MAAqB;CACnE,QAAQ,OAAR;EACE,KAAK,SACH,OAAO,KAAK;EACd,KAAK,UACH,OAAO,KAAK;EACd,KAAK,gBACH,OAAO,KAAK;EACd,KAAK,UACH,OAAO,KAAK;EACd,KAAK,qBACH,OAAO,KAAK;CAChB;CACA,OAAO,MAAM,oDAAoD;CACjE,MAAM,IAAI,MAAM,kBAAkB;AACpC"}
1
+ {"version":3,"file":"utils.js","names":["hostRules.find"],"sources":["../../../../lib/modules/platform/forgejo/utils.ts"],"sourcesContent":["import { isNonEmptyArray } from '@sindresorhus/is';\nimport type { MergeStrategy } from '../../../config/types.ts';\nimport { CONFIG_GIT_URL_UNAVAILABLE } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport * as hostRules from '../../../util/host-rules.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { parseUrl } from '../../../util/url.ts';\nimport { getPrBodyStruct } from '../pr-body.ts';\nimport type { GitUrlOption, Pr } from '../types.ts';\nimport type { PR, PRMergeMethod, Repo } from './schema.ts';\n\nexport function smartLinks(body: string): string {\n return body\n ?.replace(regEx(/\\]\\(\\.\\.\\/issues\\//g), '](issues/')\n .replace(regEx(/\\]\\(\\.\\.\\/pull\\//g), '](pulls/');\n}\n\nexport function trimTrailingApiPath(url: string): string {\n return url?.replace(regEx(/api\\/v1\\/?$/g), '');\n}\n\nexport function getRepoUrl(\n repo: Repo,\n gitUrl: GitUrlOption | undefined,\n endpoint: string,\n): string {\n if (gitUrl === 'ssh') {\n if (!repo.ssh_url) {\n throw new Error(CONFIG_GIT_URL_UNAVAILABLE);\n }\n logger.debug(`Using SSH URL: ${repo.ssh_url}`);\n return repo.ssh_url;\n }\n\n // Find options for current host and determine Git endpoint\n const opts = hostRules.find({\n hostType: 'forgejo',\n url: endpoint,\n });\n\n if (gitUrl === 'endpoint') {\n const url = parseUrl(endpoint);\n if (!url) {\n throw new Error(CONFIG_GIT_URL_UNAVAILABLE);\n }\n url.username = opts.token ?? '';\n url.pathname = `${url.pathname}${repo.full_name}.git`;\n logger.debug(\n { url: url.toString() },\n 'using URL based on configured endpoint',\n );\n return url.toString();\n }\n\n if (!repo.clone_url) {\n throw new Error(CONFIG_GIT_URL_UNAVAILABLE);\n }\n\n logger.debug(`Using HTTP URL: ${repo.clone_url}`);\n const repoUrl = parseUrl(repo.clone_url);\n if (!repoUrl) {\n throw new Error(CONFIG_GIT_URL_UNAVAILABLE);\n }\n repoUrl.username = opts.token ?? '';\n return repoUrl.toString();\n}\n\nexport function getMergeMethod(\n strategy: MergeStrategy | undefined,\n): PRMergeMethod | null {\n switch (strategy) {\n case 'fast-forward':\n return 'rebase';\n case 'merge-commit':\n return 'merge';\n case 'rebase':\n return 'rebase-merge';\n case 'squash':\n return strategy;\n case 'auto':\n default:\n return null;\n }\n}\n\nexport const API_PATH = '/api/v1';\n\nexport const DRAFT_PREFIX = 'WIP: ';\nconst reconfigurePrRegex = regEx(/reconfigure$/g);\n\nexport function toRenovatePR(data: PR, author: string | null): Pr | null {\n if (\n !data.base?.ref ||\n !data.head?.label ||\n !data.head?.sha ||\n !data.head?.repo?.full_name\n ) {\n logger.trace(\n `Skipping Pull Request #${data.number} due to missing base and/or head branch`,\n );\n return null;\n }\n\n const createdBy = data.user?.login;\n if (\n createdBy &&\n author &&\n !reconfigurePrRegex.test(data.head.label) &&\n createdBy !== author\n ) {\n return null;\n }\n\n let title = data.title;\n let isDraft = false;\n if (title.startsWith(DRAFT_PREFIX)) {\n title = title.substring(DRAFT_PREFIX.length);\n isDraft = true;\n }\n const labels = coerceArray(data.labels).map((l) => l.name);\n\n return {\n labels,\n number: data.number,\n state: data.merged ? 'merged' : data.state,\n title,\n isDraft,\n bodyStruct: getPrBodyStruct(data.body),\n sha: data.head.sha,\n sourceBranch: data.head.label,\n targetBranch: data.base.ref,\n sourceRepo: data.head.repo.full_name,\n createdAt: data.created_at,\n cannotMergeReason: data.mergeable\n ? undefined\n : `pr.mergeable=\"${data.mergeable}\"`,\n hasAssignees: !!(data.assignee?.login ?? isNonEmptyArray(data.assignees)),\n };\n}\n\n/**\n * Check if a repository is usable.\n * A repo isn't usable if one of the following conditions is met:\n * - The repo is a `mirror`\n * - We don't have pull or push permissions\n * - Pull requests are disabled\n * @param repo Repo to check\n * @returns `true` if the repository is usable, `false` otherwise\n */\nexport function usableRepo(repo: Repo): boolean {\n if (repo.mirror === true) {\n return false;\n }\n\n if (repo.permissions.pull === false || repo.permissions.push === false) {\n logger.debug(\n `Skipping repository ${repo.full_name} because of missing pull or push permissions`,\n );\n return false;\n }\n\n if (repo.has_pull_requests === false) {\n logger.debug(\n `Skipping repository ${repo.full_name} because pull requests are disabled`,\n );\n return false;\n }\n return true;\n}\n\nexport function isAllowed(style: PRMergeMethod, repo: Repo): boolean {\n switch (style) {\n case 'merge':\n return repo.allow_merge_commits;\n case 'rebase':\n return repo.allow_rebase;\n case 'rebase-merge':\n return repo.allow_rebase_explicit;\n case 'squash':\n return repo.allow_squash_merge;\n case 'fast-forward-only':\n return repo.allow_fast_forward_only_merge;\n }\n}\n"],"mappings":"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"}
@@ -2,8 +2,8 @@ import { fromBase64 } from "../../../../../../util/string.js";
2
2
  import { logger } from "../../../../../../logger/index.js";
3
3
  import { ForgejoHttp } from "../../../../../../util/http/forgejo.js";
4
4
  import { Releases } from "../../../../../../modules/datasource/forgejo-releases/schema.js";
5
+ import { ContentsListResponse, RepoContents } from "../../../../../../modules/platform/forgejo/schema.js";
5
6
  import { compareChangelogFilePath } from "../common.js";
6
- import { ContentsListResponse, ContentsResponse } from "../../../../../../modules/platform/gitea/schema.js";
7
7
  import changelogFilenameRegex from "changelog-filename-regex";
8
8
  const http = new ForgejoHttp("forgejo-changelog");
9
9
  async function getReleaseNotesMd(repository, apiBaseUrl, sourceDirectory) {
@@ -20,9 +20,9 @@ async function getReleaseNotesMd(repository, apiBaseUrl, sourceDirectory) {
20
20
  const { path: changelogFile } = files.sort((a, b) => compareChangelogFilePath(a.path, b.path)).shift();
21
21
  /* istanbul ignore if */
22
22
  if (files.length !== 0) logger.debug(`Multiple candidates for changelog file, using ${changelogFile}`);
23
- const fileRes = await http.getJson(`${apiPrefix}/${changelogFile}`, ContentsResponse);
23
+ const fileRes = await http.getJson(`${apiPrefix}/${changelogFile}`, RepoContents);
24
24
  // istanbul ignore if: should never happen
25
- if (!fileRes.body.content) {
25
+ if (fileRes.body.type !== "file" || !fileRes.body.content) {
26
26
  logger.debug(`Missing content for changelog file, using ${changelogFile}`);
27
27
  return null;
28
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../../../../lib/workers/repository/update/pr/changelog/forgejo/index.ts"],"sourcesContent":["import changelogFilenameRegex from 'changelog-filename-regex';\nimport { logger } from '../../../../../../logger/index.ts';\nimport { Releases } from '../../../../../../modules/datasource/forgejo-releases/schema.ts';\nimport {\n ContentsListResponse,\n ContentsResponse,\n} from '../../../../../../modules/platform/gitea/schema.ts';\nimport { ForgejoHttp } from '../../../../../../util/http/forgejo.ts';\nimport { fromBase64 } from '../../../../../../util/string.ts';\nimport { compareChangelogFilePath } from '../common.ts';\nimport type {\n ChangeLogFile,\n ChangeLogNotes,\n ChangeLogProject,\n ChangeLogRelease,\n} from '../types.ts';\n\nexport const id = 'forgejo-changelog';\nconst http = new ForgejoHttp(id);\n\nexport async function getReleaseNotesMd(\n repository: string,\n apiBaseUrl: string,\n sourceDirectory?: string,\n): Promise<ChangeLogFile | null> {\n logger.trace('forgejo.getReleaseNotesMd()');\n const apiPrefix = `${apiBaseUrl}repos/${repository}/contents`;\n\n const sourceDir = sourceDirectory ? `/${sourceDirectory}` : '';\n const tree = (\n await http.getJson(\n `${apiPrefix}${sourceDir}`,\n {\n paginate: false, // no pagination yet\n },\n ContentsListResponse,\n )\n ).body;\n const allFiles = tree.filter((f) => f.type === 'file');\n let files: ContentsResponse[] = [];\n if (!files.length) {\n files = allFiles.filter((f) => changelogFilenameRegex.test(f.name));\n }\n if (!files.length) {\n logger.trace('no changelog file found');\n return null;\n }\n\n const { path: changelogFile } = files\n .sort((a, b) => compareChangelogFilePath(a.path, b.path))\n .shift()!;\n /* istanbul ignore if */\n if (files.length !== 0) {\n logger.debug(\n `Multiple candidates for changelog file, using ${changelogFile}`,\n );\n }\n\n const fileRes = await http.getJson(\n `${apiPrefix}/${changelogFile}`,\n ContentsResponse,\n );\n // istanbul ignore if: should never happen\n if (!fileRes.body.content) {\n logger.debug(`Missing content for changelog file, using ${changelogFile}`);\n return null;\n }\n const changelogMd = `${fromBase64(fileRes.body.content)}\\n#\\n##`;\n\n return { changelogFile, changelogMd };\n}\n\nexport async function getReleaseList(\n project: ChangeLogProject,\n _release: ChangeLogRelease,\n): Promise<ChangeLogNotes[]> {\n logger.trace('forgejo.getReleaseNotesMd()');\n const apiUrl = `${project.apiBaseUrl}repos/${project.repository}/releases`;\n\n const res = await http.getJson(\n `${apiUrl}?draft=false`,\n {\n paginate: true,\n },\n Releases,\n );\n return res.body.map((release) => ({\n url: `${project.baseUrl}${project.repository}/releases/tag/${release.tag_name}`,\n notesSourceUrl: apiUrl,\n name: release.name,\n body: release.body,\n tag: release.tag_name,\n }));\n}\n"],"mappings":";;;;;;;AAkBA,MAAM,OAAO,IAAI,YAAY,mBAAE;AAE/B,eAAsB,kBACpB,YACA,YACA,iBAC+B;CAC/B,OAAO,MAAM,6BAA6B;CAC1C,MAAM,YAAY,GAAG,WAAW,QAAQ,WAAW;CAEnD,MAAM,YAAY,kBAAkB,IAAI,oBAAoB;CAU5D,MAAM,YARJ,MAAM,KAAK,QACT,GAAG,YAAY,aACf,EACE,UAAU,MACZ,GACA,oBACF,EAAA,CACA,KACoB,QAAQ,MAAM,EAAE,SAAS,MAAM;CACrD,IAAI,QAA4B,CAAC;CACjC,IAAI,CAAC,MAAM,QACT,QAAQ,SAAS,QAAQ,MAAM,uBAAuB,KAAK,EAAE,IAAI,CAAC;CAEpE,IAAI,CAAC,MAAM,QAAQ;EACjB,OAAO,MAAM,yBAAyB;EACtC,OAAO;CACT;CAEA,MAAM,EAAE,MAAM,kBAAkB,MAC7B,MAAM,GAAG,MAAM,yBAAyB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CACxD,MAAM;;CAET,IAAI,MAAM,WAAW,GACnB,OAAO,MACL,iDAAiD,eACnD;CAGF,MAAM,UAAU,MAAM,KAAK,QACzB,GAAG,UAAU,GAAG,iBAChB,gBACF;;CAEA,IAAI,CAAC,QAAQ,KAAK,SAAS;EACzB,OAAO,MAAM,6CAA6C,eAAe;EACzE,OAAO;CACT;CAGA,OAAO;EAAE;EAAe,aAAA,GAFD,WAAW,QAAQ,KAAK,OAAO,EAAE;CAEpB;AACtC;AAEA,eAAsB,eACpB,SACA,UAC2B;CAC3B,OAAO,MAAM,6BAA6B;CAC1C,MAAM,SAAS,GAAG,QAAQ,WAAW,QAAQ,QAAQ,WAAW;CAShE,QAAO,MAPW,KAAK,QACrB,GAAG,OAAO,eACV,EACE,UAAU,KACZ,GACA,QACF,EAAA,CACW,KAAK,KAAK,aAAa;EAChC,KAAK,GAAG,QAAQ,UAAU,QAAQ,WAAW,gBAAgB,QAAQ;EACrE,gBAAgB;EAChB,MAAM,QAAQ;EACd,MAAM,QAAQ;EACd,KAAK,QAAQ;CACf,EAAE;AACJ"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../../../../lib/workers/repository/update/pr/changelog/forgejo/index.ts"],"sourcesContent":["import changelogFilenameRegex from 'changelog-filename-regex';\nimport { logger } from '../../../../../../logger/index.ts';\nimport { Releases } from '../../../../../../modules/datasource/forgejo-releases/schema.ts';\nimport {\n ContentsListResponse,\n RepoContents,\n} from '../../../../../../modules/platform/forgejo/schema.ts';\nimport { ForgejoHttp } from '../../../../../../util/http/forgejo.ts';\nimport { fromBase64 } from '../../../../../../util/string.ts';\nimport { compareChangelogFilePath } from '../common.ts';\nimport type {\n ChangeLogFile,\n ChangeLogNotes,\n ChangeLogProject,\n ChangeLogRelease,\n} from '../types.ts';\n\nexport const id = 'forgejo-changelog';\nconst http = new ForgejoHttp(id);\n\nexport async function getReleaseNotesMd(\n repository: string,\n apiBaseUrl: string,\n sourceDirectory?: string,\n): Promise<ChangeLogFile | null> {\n logger.trace('forgejo.getReleaseNotesMd()');\n const apiPrefix = `${apiBaseUrl}repos/${repository}/contents`;\n\n const sourceDir = sourceDirectory ? `/${sourceDirectory}` : '';\n const tree = (\n await http.getJson(\n `${apiPrefix}${sourceDir}`,\n {\n paginate: false, // no pagination yet\n },\n ContentsListResponse,\n )\n ).body;\n const allFiles = tree.filter((f) => f.type === 'file');\n let files: RepoContents[] = [];\n if (!files.length) {\n files = allFiles.filter((f) => changelogFilenameRegex.test(f.name));\n }\n if (!files.length) {\n logger.trace('no changelog file found');\n return null;\n }\n\n const { path: changelogFile } = files\n .sort((a, b) => compareChangelogFilePath(a.path, b.path))\n .shift()!;\n /* istanbul ignore if */\n if (files.length !== 0) {\n logger.debug(\n `Multiple candidates for changelog file, using ${changelogFile}`,\n );\n }\n\n const fileRes = await http.getJson(\n `${apiPrefix}/${changelogFile}`,\n RepoContents,\n );\n // istanbul ignore if: should never happen\n if (fileRes.body.type !== 'file' || !fileRes.body.content) {\n logger.debug(`Missing content for changelog file, using ${changelogFile}`);\n return null;\n }\n const changelogMd = `${fromBase64(fileRes.body.content)}\\n#\\n##`;\n\n return { changelogFile, changelogMd };\n}\n\nexport async function getReleaseList(\n project: ChangeLogProject,\n _release: ChangeLogRelease,\n): Promise<ChangeLogNotes[]> {\n logger.trace('forgejo.getReleaseNotesMd()');\n const apiUrl = `${project.apiBaseUrl}repos/${project.repository}/releases`;\n\n const res = await http.getJson(\n `${apiUrl}?draft=false`,\n {\n paginate: true,\n },\n Releases,\n );\n return res.body.map((release) => ({\n url: `${project.baseUrl}${project.repository}/releases/tag/${release.tag_name}`,\n notesSourceUrl: apiUrl,\n name: release.name,\n body: release.body,\n tag: release.tag_name,\n }));\n}\n"],"mappings":";;;;;;;AAkBA,MAAM,OAAO,IAAI,YAAY,mBAAE;AAE/B,eAAsB,kBACpB,YACA,YACA,iBAC+B;CAC/B,OAAO,MAAM,6BAA6B;CAC1C,MAAM,YAAY,GAAG,WAAW,QAAQ,WAAW;CAEnD,MAAM,YAAY,kBAAkB,IAAI,oBAAoB;CAU5D,MAAM,YARJ,MAAM,KAAK,QACT,GAAG,YAAY,aACf,EACE,UAAU,MACZ,GACA,oBACF,EAAA,CACA,KACoB,QAAQ,MAAM,EAAE,SAAS,MAAM;CACrD,IAAI,QAAwB,CAAC;CAC7B,IAAI,CAAC,MAAM,QACT,QAAQ,SAAS,QAAQ,MAAM,uBAAuB,KAAK,EAAE,IAAI,CAAC;CAEpE,IAAI,CAAC,MAAM,QAAQ;EACjB,OAAO,MAAM,yBAAyB;EACtC,OAAO;CACT;CAEA,MAAM,EAAE,MAAM,kBAAkB,MAC7B,MAAM,GAAG,MAAM,yBAAyB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CACxD,MAAM;;CAET,IAAI,MAAM,WAAW,GACnB,OAAO,MACL,iDAAiD,eACnD;CAGF,MAAM,UAAU,MAAM,KAAK,QACzB,GAAG,UAAU,GAAG,iBAChB,YACF;;CAEA,IAAI,QAAQ,KAAK,SAAS,UAAU,CAAC,QAAQ,KAAK,SAAS;EACzD,OAAO,MAAM,6CAA6C,eAAe;EACzE,OAAO;CACT;CAGA,OAAO;EAAE;EAAe,aAAA,GAFD,WAAW,QAAQ,KAAK,OAAO,EAAE;CAEpB;AACtC;AAEA,eAAsB,eACpB,SACA,UAC2B;CAC3B,OAAO,MAAM,6BAA6B;CAC1C,MAAM,SAAS,GAAG,QAAQ,WAAW,QAAQ,QAAQ,WAAW;CAShE,QAAO,MAPW,KAAK,QACrB,GAAG,OAAO,eACV,EACE,UAAU,KACZ,GACA,QACF,EAAA,CACW,KAAK,KAAK,aAAa;EAChC,KAAK,GAAG,QAAQ,UAAU,QAAQ,WAAW,gBAAgB,QAAQ;EACrE,gBAAgB;EAChB,MAAM,QAAQ;EACd,MAAM,QAAQ;EACd,KAAK,QAAQ;CACf,EAAE;AACJ"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "renovate",
3
3
  "description": "Automated dependency updates. Flexible so you don't need to be.",
4
- "version": "43.226.2",
4
+ "version": "43.227.1",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "renovate": "dist/renovate.js",
@@ -181,7 +181,7 @@
181
181
  "p-throttle": "8.1.0",
182
182
  "parse-link-header": "2.0.0",
183
183
  "prettier": "3.8.1",
184
- "protobufjs": "8.6.1",
184
+ "protobufjs": "8.6.2",
185
185
  "punycode": "2.3.1",
186
186
  "remark": "15.0.1",
187
187
  "remark-gfm": "4.0.1",
@@ -276,7 +276,7 @@
276
276
  "oxlint": "1.69.0",
277
277
  "oxlint-tsgolint": "0.23.0",
278
278
  "rimraf": "6.1.3",
279
- "semantic-release": "25.0.3",
279
+ "semantic-release": "25.0.5",
280
280
  "tar": "7.5.16",
281
281
  "tmp-promise": "3.0.3",
282
282
  "tsdown": "0.22.2",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$id": "https://docs.renovatebot.com/renovate-schema.json",
3
- "title": "JSON schema for Renovate 43.226.2 config files (https://renovatebot.com/)",
3
+ "title": "JSON schema for Renovate 43.227.1 config files (https://renovatebot.com/)",
4
4
  "$schema": "http://json-schema.org/draft-07/schema#",
5
- "x-renovate-version": "43.226.2",
5
+ "x-renovate-version": "43.227.1",
6
6
  "allowComments": true,
7
7
  "type": "object",
8
8
  "definitions": {