renovate 43.264.2 → 43.265.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config-validator.js.map +1 -1
- package/dist/modules/datasource/bitrise/index.js +1 -1
- package/dist/modules/datasource/bitrise/index.js.map +1 -1
- package/dist/modules/datasource/custom/index.js +8 -2
- package/dist/modules/datasource/custom/index.js.map +1 -1
- package/dist/modules/datasource/postprocess-release.js +4 -1
- package/dist/modules/datasource/postprocess-release.js.map +1 -1
- package/dist/modules/manager/bazel-module/lockfile.js +1 -1
- package/dist/modules/manager/bazel-module/lockfile.js.map +1 -1
- package/dist/modules/manager/deno/artifacts.js +5 -1
- package/dist/modules/manager/deno/artifacts.js.map +1 -1
- package/dist/modules/manager/deno/post.js +1 -1
- package/dist/modules/manager/deno/post.js.map +1 -1
- package/dist/modules/manager/fingerprint.generated.js +2 -2
- package/dist/modules/manager/fingerprint.generated.js.map +1 -1
- package/dist/modules/manager/gradle/artifacts.js +1 -1
- package/dist/modules/manager/gradle/artifacts.js.map +1 -1
- package/dist/modules/manager/mise/artifacts.js +4 -1
- package/dist/modules/manager/mise/artifacts.js.map +1 -1
- package/dist/modules/platform/azure/issue.js +4 -1
- package/dist/modules/platform/azure/issue.js.map +1 -1
- package/dist/modules/platform/bitbucket/index.js +4 -1
- package/dist/modules/platform/bitbucket/index.js.map +1 -1
- package/dist/modules/platform/codecommit/index.js +2 -2
- package/dist/modules/platform/codecommit/index.js.map +1 -1
- package/dist/modules/platform/gitlab/http.js +1 -1
- package/dist/modules/platform/gitlab/http.js.map +1 -1
- package/dist/modules/platform/scm-manager/index.js +5 -2
- package/dist/modules/platform/scm-manager/index.js.map +1 -1
- package/dist/util/emoji.js +2 -2
- package/dist/util/emoji.js.map +1 -1
- package/dist/util/http/github.js +2 -2
- package/dist/util/http/github.js.map +1 -1
- package/dist/util/interpolator.js +4 -1
- package/dist/util/interpolator.js.map +1 -1
- package/dist/workers/global/config/parse/additional-config-file.js +1 -1
- package/dist/workers/global/config/parse/additional-config-file.js.map +1 -1
- package/dist/workers/global/config/parse/env.js +4 -1
- package/dist/workers/global/config/parse/env.js.map +1 -1
- package/dist/workers/global/config/parse/file.js +1 -1
- package/dist/workers/global/config/parse/file.js.map +1 -1
- package/dist/workers/repository/error.js +3 -3
- package/dist/workers/repository/error.js.map +1 -1
- package/dist/workers/repository/process/extract-update.js +2 -2
- package/dist/workers/repository/process/extract-update.js.map +1 -1
- package/dist/workers/repository/update/branch/bump-versions.js +5 -1
- package/dist/workers/repository/update/branch/bump-versions.js.map +1 -1
- package/dist/workers/repository/update/branch/execute-post-upgrade-commands.js +1 -1
- package/dist/workers/repository/update/branch/execute-post-upgrade-commands.js.map +1 -1
- package/dist/workers/repository/update/branch/get-updated.js +3 -3
- package/dist/workers/repository/update/branch/get-updated.js.map +1 -1
- package/dist/workers/repository/updates/branch-name.js +1 -1
- package/dist/workers/repository/updates/branch-name.js.map +1 -1
- package/package.json +1 -1
- package/renovate-schema.json +2 -2
|
@@ -220,7 +220,10 @@ var IssueService = class {
|
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
if (!await this.hasWorkItemType(azureApiWit)) {
|
|
223
|
-
logger.warn(
|
|
223
|
+
logger.warn({
|
|
224
|
+
workItemType,
|
|
225
|
+
project: this.config.project
|
|
226
|
+
}, "Azure: work item type does not exist in project (or the token lacks permission to it); skipping issue. The Dependency Dashboard needs a process that defines this work item type.");
|
|
224
227
|
return null;
|
|
225
228
|
}
|
|
226
229
|
const newWorkItem = await azureApiWit.createWorkItem(void 0, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.js","names":["azureApi.workItemTrackingApi"],"sources":["../../../../lib/modules/platform/azure/issue.ts"],"sourcesContent":["import type {\n WorkItem,\n WorkItemStateColor,\n} from 'azure-devops-node-api/interfaces/WorkItemTrackingInterfaces.js';\nimport type { IWorkItemTrackingApi } from 'azure-devops-node-api/WorkItemTrackingApi.js';\nimport { logger } from '../../../logger/index.ts';\nimport { Lazy } from '../../../util/lazy.ts';\nimport { sanitize } from '../../../util/sanitize.ts';\nimport type { EnsureIssueConfig, EnsureIssueResult, Issue } from '../types.ts';\nimport * as azureApi from './azure-got-wrapper.ts';\nimport type { Config } from './types.ts';\nimport { getWorkItemTitle } from './util.ts';\n\nconst workItemType = 'Issue';\n\n// Historical fallbacks, used when the work item type's states cannot be\n// resolved from the API (e.g. Azure DevOps Server versions without the\n// endpoint). These match the values Renovate hardcoded previously.\nconst defaultOpenState = 'New';\nconst defaultClosedState = 'Closed';\n\n// Azure Boards groups every work item state into one of these meta-state\n// categories. Which concrete state name maps to a category depends on the\n// project's process (Basic: To Do/Doing/Done, Agile: New/Active/.../Closed,\n// custom inherited processes: anything). Categories are stable, so we resolve\n// the concrete names from them instead of hardcoding process-specific values.\nconst openCategories = ['Proposed', 'InProgress'];\nconst closedCategories = ['Completed', 'Resolved', 'Removed'];\n\ninterface WorkItemStates {\n /** State to move a work item to when (re)opening it. */\n open: string;\n /** State to move a work item to when closing it. */\n closed: string;\n /** All state names that represent a closed/completed work item. */\n closedNames: Set<string>;\n}\n\n/**\n * Return the names of the states whose category is one of `categories`,\n * preserving the order Azure DevOps returns them in (workflow order).\n */\nfunction namesByCategory(\n stateColors: WorkItemStateColor[],\n categories: string[],\n): string[] {\n return stateColors\n .filter((s) => s.category && categories.includes(s.category) && s.name)\n .map((s) => s.name!);\n}\n\nexport class IssueService {\n private config: Config;\n private readonly workItemStates: Lazy<Promise<WorkItemStates>>;\n\n constructor(config: Config) {\n this.config = config;\n // Wrapped in `Lazy` so concurrent callers share a single resolution\n // instead of each firing a duplicate `getWorkItemTypeStates` request.\n this.workItemStates = new Lazy(() => this.resolveWorkItemStates());\n }\n\n /**\n * Resolve the concrete open/closed state names for the `Issue` work item type\n * from its process, so Renovate does not depend on hardcoded state names that\n * only exist in some Azure DevOps processes. Falls back to the historical\n * `New`/`Closed` values if the states cannot be fetched.\n */\n private async resolveWorkItemStates(): Promise<WorkItemStates> {\n const states: WorkItemStates = {\n open: defaultOpenState,\n closed: defaultClosedState,\n closedNames: new Set([defaultClosedState]),\n };\n\n try {\n const azureApiWit = await azureApi.workItemTrackingApi();\n const stateColors = await azureApiWit.getWorkItemTypeStates(\n this.config.project,\n workItemType,\n );\n\n if (stateColors?.length) {\n const openNames = namesByCategory(stateColors, openCategories);\n // A `Completed` state (e.g. Agile's `Closed`) is the true \"done\" state.\n // `Resolved`/`Removed` states also count as closed but must not be\n // picked over `Completed` when moving an item to closed.\n const completed = stateColors.find(\n (s) => s.category === 'Completed' && s.name,\n );\n const closedNames = namesByCategory(stateColors, closedCategories);\n\n // First open-category state, else the type's first state overall. If a\n // process somehow exposes only closed states, this falls back to a\n // closed state name; that is intentional (there is no better reopen\n // target) rather than a bug.\n states.open = openNames[0] ?? stateColors[0].name ?? states.open;\n if (closedNames.length) {\n // Prefer a `Completed` state as the close target so processes that\n // order `Resolved` before `Closed` (e.g. some custom Agile\n // inheritances) still close to `Closed`; fall back to the wider set\n // only when no `Completed` state exists. Keep the full set for\n // recognising already-closed items.\n states.closed = completed?.name ?? closedNames[0];\n states.closedNames = new Set(closedNames);\n }\n }\n } catch (err) {\n logger.debug(\n { err },\n 'Azure: could not resolve work item states, using default state names',\n );\n }\n\n return states;\n }\n\n async findIssue(title: string): Promise<Issue | null> {\n logger.debug(`findIssue(${title})`);\n try {\n const finalTitle = getWorkItemTitle(title, this.config.repository);\n const issues = await this.getIssueList(finalTitle);\n return issues[0] ?? null;\n } catch (err) {\n logger.error({ err }, 'Error finding issue');\n return null;\n }\n }\n\n /**\n * Whether the project's process defines the `Issue` work item type. Some\n * processes (e.g. Scrum) do not, in which case creating one fails; checking\n * up front lets us log an actionable message instead of a cryptic error.\n */\n private async hasWorkItemType(\n azureApiWit: IWorkItemTrackingApi,\n ): Promise<boolean> {\n const types = await azureApiWit.getWorkItemTypes(this.config.project);\n return types.some((t) => t.name === workItemType);\n }\n\n async getIssueList(titleFilter?: string): Promise<Issue[]> {\n logger.debug('getIssueList()');\n try {\n const azureApiWit = await azureApi.workItemTrackingApi();\n\n let wiql = `\n SELECT [System.Id]\n FROM WorkItems\n WHERE [System.WorkItemType] = '${workItemType}'\n AND [System.TeamProject] = '${this.config.project}'\n `;\n\n if (titleFilter) {\n const escapedTitle = titleFilter.replace(/'/g, \"''\");\n wiql += ` AND [System.Title] = '${escapedTitle}'`;\n }\n\n const result = await azureApiWit.queryByWiql({ query: wiql });\n\n if (!result.workItems?.length) {\n logger.debug('getIssueList() no work items found');\n return [];\n }\n\n const workItemIds = result.workItems.map((wi: WorkItem) => wi.id!);\n const workItems = await azureApiWit.getWorkItems(workItemIds, [\n 'System.Id',\n 'System.Title',\n 'System.State',\n 'System.Description',\n 'System.CreatedDate',\n 'System.ChangedDate',\n ]);\n\n const { closedNames } = await this.workItemStates.getValue();\n\n return workItems.map((wi: WorkItem) => ({\n number: wi.id!,\n title: wi.fields!['System.Title'],\n state: closedNames.has(wi.fields!['System.State']) ? 'closed' : 'open',\n body: wi.fields!['System.Description'],\n createdAt: wi.fields!['System.CreatedDate'],\n lastModified: wi.fields!['System.ChangedDate'],\n }));\n } catch (err) {\n logger.warn({ err }, 'Error fetching issue list');\n return [];\n }\n }\n\n async ensureIssueClosing(title: string): Promise<void> {\n logger.debug(`ensureIssueClosing(${title})`);\n try {\n const issue = await this.findIssue(title);\n if (issue?.state === 'open' && issue.number) {\n const azureApiWit = await azureApi.workItemTrackingApi();\n const { closed } = await this.workItemStates.getValue();\n await azureApiWit.updateWorkItem(\n undefined,\n [{ op: 'replace', path: '/fields/System.State', value: closed }],\n issue.number,\n this.config.project,\n );\n logger.debug(`Closed issue #${issue.number}: ${title}`);\n }\n } catch (err) {\n logger.error({ err }, 'Error closing issue');\n }\n }\n\n async ensureIssue({\n title,\n body,\n once = false,\n shouldReOpen = true,\n }: EnsureIssueConfig): Promise<EnsureIssueResult | null> {\n logger.debug(`ensureIssue()`);\n\n try {\n const azureApiWit = await azureApi.workItemTrackingApi();\n const finalTitle = getWorkItemTitle(title, this.config.repository);\n const issues = await this.getIssueList(finalTitle);\n const { open, closed } = await this.workItemStates.getValue();\n\n // Close duplicate open issues if any\n const openIssues = issues.filter((issue) => issue.state === 'open');\n if (openIssues.length > 1) {\n for (let i = 1; i < openIssues.length; i++) {\n const issueNumber = openIssues[i].number;\n if (issueNumber) {\n await azureApiWit.updateWorkItem(\n undefined,\n [\n {\n op: 'replace',\n path: '/fields/System.State',\n value: closed,\n },\n ],\n issueNumber,\n this.config.project,\n );\n logger.info(`Closed duplicate issue #${issueNumber}`);\n }\n }\n }\n\n const existingIssue =\n openIssues[0] ?? issues.find((issue) => issue.state === 'closed');\n\n if (existingIssue) {\n if (existingIssue.state === 'closed' && once) {\n logger.debug('Issue already closed - skipping update');\n return null;\n }\n if (existingIssue.state === 'closed' && shouldReOpen) {\n // Reopen and update work item\n if (!existingIssue.number) {\n logger.warn('Cannot reopen issue without number');\n return null;\n }\n await azureApiWit.updateWorkItem(\n undefined,\n [\n { op: 'replace', path: '/fields/System.State', value: open },\n {\n op: 'replace',\n path: '/fields/System.Title',\n value: finalTitle,\n },\n {\n op: 'replace',\n path: '/fields/System.Description',\n value: sanitize(body),\n },\n {\n op: 'replace',\n path: '/multilineFieldsFormat/System.Description',\n value: 'Markdown',\n },\n ],\n existingIssue.number,\n this.config.project,\n );\n logger.debug(`Reopened issue #${existingIssue.number}`);\n return 'updated';\n }\n if (existingIssue.state === 'open') {\n // Update work item if needed\n if (\n existingIssue.title !== finalTitle ||\n existingIssue.body !== body\n ) {\n if (!existingIssue.number) {\n logger.warn('Cannot update issue without number');\n return null;\n }\n await azureApiWit.updateWorkItem(\n undefined,\n [\n {\n op: 'replace',\n path: '/fields/System.Title',\n value: finalTitle,\n },\n {\n op: 'replace',\n path: '/fields/System.Description',\n value: sanitize(body),\n },\n {\n op: 'replace',\n path: '/multilineFieldsFormat/System.Description',\n value: 'Markdown',\n },\n ],\n existingIssue.number,\n this.config.project,\n );\n logger.debug(`Updated issue #${existingIssue.number}`);\n return 'updated';\n }\n logger.debug(`Issue #${existingIssue.number} is already up-to-date`);\n return 'updated';\n }\n }\n\n // Create new work item if none found. System.State is intentionally\n // omitted so Azure DevOps applies the work item type's default initial\n // state for the project's process (e.g. `To Do` on Basic, `New`/`Active`\n // on Agile). Passing a hardcoded state fails on processes that lack it.\n\n // The `Issue` work item type only exists in some processes (Basic, Agile,\n // CMMI) but not others (e.g. Scrum). Creating one on a process without it\n // returns a 404 that the REST client surfaces as `null`, so check first\n // and log an actionable message instead of failing cryptically.\n if (!(await this.hasWorkItemType(azureApiWit))) {\n logger.warn(\n `Azure: work item type '${workItemType}' does not exist in project '${this.config.project}' (or the token lacks permission to it); skipping issue. The Dependency Dashboard needs a process that defines the '${workItemType}' work item type.`,\n );\n return null;\n }\n\n const newWorkItem = await azureApiWit.createWorkItem(\n undefined,\n [\n {\n op: 'add',\n path: '/fields/System.WorkItemType',\n value: workItemType,\n },\n { op: 'add', path: '/fields/System.Title', value: finalTitle },\n {\n op: 'add',\n path: '/fields/System.Description',\n value: sanitize(body),\n },\n {\n op: 'add',\n path: '/multilineFieldsFormat/System.Description',\n value: 'Markdown',\n },\n ],\n this.config.project,\n workItemType,\n );\n\n // Azure DevOps normally returns the created work item, but the\n // underlying REST client resolves to `null` instead of throwing for\n // some responses: a 404, or any 2xx with an empty/non-JSON body (e.g. a\n // 203 sign-in page from an expired token or an SSO/proxy in front of the\n // instance). Guard the result so such a response does not crash the whole\n // run with `Cannot read properties of null (reading 'id')`.\n if (!newWorkItem?.id) {\n logger.warn(\n 'Azure: work item creation returned no result; skipping issue',\n );\n return null;\n }\n\n logger.debug(`Created new issue #${newWorkItem.id}`);\n return 'created';\n } catch (err) {\n logger.warn({ err }, 'Error ensuring issue');\n return null;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"issue.js","names":["azureApi.workItemTrackingApi"],"sources":["../../../../lib/modules/platform/azure/issue.ts"],"sourcesContent":["import type {\n WorkItem,\n WorkItemStateColor,\n} from 'azure-devops-node-api/interfaces/WorkItemTrackingInterfaces.js';\nimport type { IWorkItemTrackingApi } from 'azure-devops-node-api/WorkItemTrackingApi.js';\nimport { logger } from '../../../logger/index.ts';\nimport { Lazy } from '../../../util/lazy.ts';\nimport { sanitize } from '../../../util/sanitize.ts';\nimport type { EnsureIssueConfig, EnsureIssueResult, Issue } from '../types.ts';\nimport * as azureApi from './azure-got-wrapper.ts';\nimport type { Config } from './types.ts';\nimport { getWorkItemTitle } from './util.ts';\n\nconst workItemType = 'Issue';\n\n// Historical fallbacks, used when the work item type's states cannot be\n// resolved from the API (e.g. Azure DevOps Server versions without the\n// endpoint). These match the values Renovate hardcoded previously.\nconst defaultOpenState = 'New';\nconst defaultClosedState = 'Closed';\n\n// Azure Boards groups every work item state into one of these meta-state\n// categories. Which concrete state name maps to a category depends on the\n// project's process (Basic: To Do/Doing/Done, Agile: New/Active/.../Closed,\n// custom inherited processes: anything). Categories are stable, so we resolve\n// the concrete names from them instead of hardcoding process-specific values.\nconst openCategories = ['Proposed', 'InProgress'];\nconst closedCategories = ['Completed', 'Resolved', 'Removed'];\n\ninterface WorkItemStates {\n /** State to move a work item to when (re)opening it. */\n open: string;\n /** State to move a work item to when closing it. */\n closed: string;\n /** All state names that represent a closed/completed work item. */\n closedNames: Set<string>;\n}\n\n/**\n * Return the names of the states whose category is one of `categories`,\n * preserving the order Azure DevOps returns them in (workflow order).\n */\nfunction namesByCategory(\n stateColors: WorkItemStateColor[],\n categories: string[],\n): string[] {\n return stateColors\n .filter((s) => s.category && categories.includes(s.category) && s.name)\n .map((s) => s.name!);\n}\n\nexport class IssueService {\n private config: Config;\n private readonly workItemStates: Lazy<Promise<WorkItemStates>>;\n\n constructor(config: Config) {\n this.config = config;\n // Wrapped in `Lazy` so concurrent callers share a single resolution\n // instead of each firing a duplicate `getWorkItemTypeStates` request.\n this.workItemStates = new Lazy(() => this.resolveWorkItemStates());\n }\n\n /**\n * Resolve the concrete open/closed state names for the `Issue` work item type\n * from its process, so Renovate does not depend on hardcoded state names that\n * only exist in some Azure DevOps processes. Falls back to the historical\n * `New`/`Closed` values if the states cannot be fetched.\n */\n private async resolveWorkItemStates(): Promise<WorkItemStates> {\n const states: WorkItemStates = {\n open: defaultOpenState,\n closed: defaultClosedState,\n closedNames: new Set([defaultClosedState]),\n };\n\n try {\n const azureApiWit = await azureApi.workItemTrackingApi();\n const stateColors = await azureApiWit.getWorkItemTypeStates(\n this.config.project,\n workItemType,\n );\n\n if (stateColors?.length) {\n const openNames = namesByCategory(stateColors, openCategories);\n // A `Completed` state (e.g. Agile's `Closed`) is the true \"done\" state.\n // `Resolved`/`Removed` states also count as closed but must not be\n // picked over `Completed` when moving an item to closed.\n const completed = stateColors.find(\n (s) => s.category === 'Completed' && s.name,\n );\n const closedNames = namesByCategory(stateColors, closedCategories);\n\n // First open-category state, else the type's first state overall. If a\n // process somehow exposes only closed states, this falls back to a\n // closed state name; that is intentional (there is no better reopen\n // target) rather than a bug.\n states.open = openNames[0] ?? stateColors[0].name ?? states.open;\n if (closedNames.length) {\n // Prefer a `Completed` state as the close target so processes that\n // order `Resolved` before `Closed` (e.g. some custom Agile\n // inheritances) still close to `Closed`; fall back to the wider set\n // only when no `Completed` state exists. Keep the full set for\n // recognising already-closed items.\n states.closed = completed?.name ?? closedNames[0];\n states.closedNames = new Set(closedNames);\n }\n }\n } catch (err) {\n logger.debug(\n { err },\n 'Azure: could not resolve work item states, using default state names',\n );\n }\n\n return states;\n }\n\n async findIssue(title: string): Promise<Issue | null> {\n logger.debug(`findIssue(${title})`);\n try {\n const finalTitle = getWorkItemTitle(title, this.config.repository);\n const issues = await this.getIssueList(finalTitle);\n return issues[0] ?? null;\n } catch (err) {\n logger.error({ err }, 'Error finding issue');\n return null;\n }\n }\n\n /**\n * Whether the project's process defines the `Issue` work item type. Some\n * processes (e.g. Scrum) do not, in which case creating one fails; checking\n * up front lets us log an actionable message instead of a cryptic error.\n */\n private async hasWorkItemType(\n azureApiWit: IWorkItemTrackingApi,\n ): Promise<boolean> {\n const types = await azureApiWit.getWorkItemTypes(this.config.project);\n return types.some((t) => t.name === workItemType);\n }\n\n async getIssueList(titleFilter?: string): Promise<Issue[]> {\n logger.debug('getIssueList()');\n try {\n const azureApiWit = await azureApi.workItemTrackingApi();\n\n let wiql = `\n SELECT [System.Id]\n FROM WorkItems\n WHERE [System.WorkItemType] = '${workItemType}'\n AND [System.TeamProject] = '${this.config.project}'\n `;\n\n if (titleFilter) {\n const escapedTitle = titleFilter.replace(/'/g, \"''\");\n wiql += ` AND [System.Title] = '${escapedTitle}'`;\n }\n\n const result = await azureApiWit.queryByWiql({ query: wiql });\n\n if (!result.workItems?.length) {\n logger.debug('getIssueList() no work items found');\n return [];\n }\n\n const workItemIds = result.workItems.map((wi: WorkItem) => wi.id!);\n const workItems = await azureApiWit.getWorkItems(workItemIds, [\n 'System.Id',\n 'System.Title',\n 'System.State',\n 'System.Description',\n 'System.CreatedDate',\n 'System.ChangedDate',\n ]);\n\n const { closedNames } = await this.workItemStates.getValue();\n\n return workItems.map((wi: WorkItem) => ({\n number: wi.id!,\n title: wi.fields!['System.Title'],\n state: closedNames.has(wi.fields!['System.State']) ? 'closed' : 'open',\n body: wi.fields!['System.Description'],\n createdAt: wi.fields!['System.CreatedDate'],\n lastModified: wi.fields!['System.ChangedDate'],\n }));\n } catch (err) {\n logger.warn({ err }, 'Error fetching issue list');\n return [];\n }\n }\n\n async ensureIssueClosing(title: string): Promise<void> {\n logger.debug(`ensureIssueClosing(${title})`);\n try {\n const issue = await this.findIssue(title);\n if (issue?.state === 'open' && issue.number) {\n const azureApiWit = await azureApi.workItemTrackingApi();\n const { closed } = await this.workItemStates.getValue();\n await azureApiWit.updateWorkItem(\n undefined,\n [{ op: 'replace', path: '/fields/System.State', value: closed }],\n issue.number,\n this.config.project,\n );\n logger.debug(`Closed issue #${issue.number}: ${title}`);\n }\n } catch (err) {\n logger.error({ err }, 'Error closing issue');\n }\n }\n\n async ensureIssue({\n title,\n body,\n once = false,\n shouldReOpen = true,\n }: EnsureIssueConfig): Promise<EnsureIssueResult | null> {\n logger.debug(`ensureIssue()`);\n\n try {\n const azureApiWit = await azureApi.workItemTrackingApi();\n const finalTitle = getWorkItemTitle(title, this.config.repository);\n const issues = await this.getIssueList(finalTitle);\n const { open, closed } = await this.workItemStates.getValue();\n\n // Close duplicate open issues if any\n const openIssues = issues.filter((issue) => issue.state === 'open');\n if (openIssues.length > 1) {\n for (let i = 1; i < openIssues.length; i++) {\n const issueNumber = openIssues[i].number;\n if (issueNumber) {\n await azureApiWit.updateWorkItem(\n undefined,\n [\n {\n op: 'replace',\n path: '/fields/System.State',\n value: closed,\n },\n ],\n issueNumber,\n this.config.project,\n );\n logger.info(`Closed duplicate issue #${issueNumber}`);\n }\n }\n }\n\n const existingIssue =\n openIssues[0] ?? issues.find((issue) => issue.state === 'closed');\n\n if (existingIssue) {\n if (existingIssue.state === 'closed' && once) {\n logger.debug('Issue already closed - skipping update');\n return null;\n }\n if (existingIssue.state === 'closed' && shouldReOpen) {\n // Reopen and update work item\n if (!existingIssue.number) {\n logger.warn('Cannot reopen issue without number');\n return null;\n }\n await azureApiWit.updateWorkItem(\n undefined,\n [\n { op: 'replace', path: '/fields/System.State', value: open },\n {\n op: 'replace',\n path: '/fields/System.Title',\n value: finalTitle,\n },\n {\n op: 'replace',\n path: '/fields/System.Description',\n value: sanitize(body),\n },\n {\n op: 'replace',\n path: '/multilineFieldsFormat/System.Description',\n value: 'Markdown',\n },\n ],\n existingIssue.number,\n this.config.project,\n );\n logger.debug(`Reopened issue #${existingIssue.number}`);\n return 'updated';\n }\n if (existingIssue.state === 'open') {\n // Update work item if needed\n if (\n existingIssue.title !== finalTitle ||\n existingIssue.body !== body\n ) {\n if (!existingIssue.number) {\n logger.warn('Cannot update issue without number');\n return null;\n }\n await azureApiWit.updateWorkItem(\n undefined,\n [\n {\n op: 'replace',\n path: '/fields/System.Title',\n value: finalTitle,\n },\n {\n op: 'replace',\n path: '/fields/System.Description',\n value: sanitize(body),\n },\n {\n op: 'replace',\n path: '/multilineFieldsFormat/System.Description',\n value: 'Markdown',\n },\n ],\n existingIssue.number,\n this.config.project,\n );\n logger.debug(`Updated issue #${existingIssue.number}`);\n return 'updated';\n }\n logger.debug(`Issue #${existingIssue.number} is already up-to-date`);\n return 'updated';\n }\n }\n\n // Create new work item if none found. System.State is intentionally\n // omitted so Azure DevOps applies the work item type's default initial\n // state for the project's process (e.g. `To Do` on Basic, `New`/`Active`\n // on Agile). Passing a hardcoded state fails on processes that lack it.\n\n // The `Issue` work item type only exists in some processes (Basic, Agile,\n // CMMI) but not others (e.g. Scrum). Creating one on a process without it\n // returns a 404 that the REST client surfaces as `null`, so check first\n // and log an actionable message instead of failing cryptically.\n if (!(await this.hasWorkItemType(azureApiWit))) {\n logger.warn(\n { workItemType, project: this.config.project },\n 'Azure: work item type does not exist in project (or the token lacks permission to it); skipping issue. The Dependency Dashboard needs a process that defines this work item type.',\n );\n return null;\n }\n\n const newWorkItem = await azureApiWit.createWorkItem(\n undefined,\n [\n {\n op: 'add',\n path: '/fields/System.WorkItemType',\n value: workItemType,\n },\n { op: 'add', path: '/fields/System.Title', value: finalTitle },\n {\n op: 'add',\n path: '/fields/System.Description',\n value: sanitize(body),\n },\n {\n op: 'add',\n path: '/multilineFieldsFormat/System.Description',\n value: 'Markdown',\n },\n ],\n this.config.project,\n workItemType,\n );\n\n // Azure DevOps normally returns the created work item, but the\n // underlying REST client resolves to `null` instead of throwing for\n // some responses: a 404, or any 2xx with an empty/non-JSON body (e.g. a\n // 203 sign-in page from an expired token or an SSO/proxy in front of the\n // instance). Guard the result so such a response does not crash the whole\n // run with `Cannot read properties of null (reading 'id')`.\n if (!newWorkItem?.id) {\n logger.warn(\n 'Azure: work item creation returned no result; skipping issue',\n );\n return null;\n }\n\n logger.debug(`Created new issue #${newWorkItem.id}`);\n return 'created';\n } catch (err) {\n logger.warn({ err }, 'Error ensuring issue');\n return null;\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -66,7 +66,10 @@ let renovateUserUuid = null;
|
|
|
66
66
|
async function initPlatform({ endpoint, username, password, token }) {
|
|
67
67
|
if (!(username && password) && !token) throw new Error("Init: You must configure either a Bitbucket token or username and password");
|
|
68
68
|
if (endpoint && endpoint !== BITBUCKET_PROD_ENDPOINT) {
|
|
69
|
-
logger.warn(
|
|
69
|
+
logger.warn({
|
|
70
|
+
endpoint,
|
|
71
|
+
defaultEndpoint: BITBUCKET_PROD_ENDPOINT
|
|
72
|
+
}, "Init: Bitbucket Cloud endpoint should generally be the default but is being configured to a different value. Did you mean to use Bitbucket Server?");
|
|
70
73
|
defaults.endpoint = endpoint;
|
|
71
74
|
}
|
|
72
75
|
setBaseUrl(defaults.endpoint);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["promises.map","hostRules.find","git.getUrl","git.initRepo","utils.prInfo","reopenComments","comments.reopenComments","comments.REOPEN_PR_COMMENT_KEYWORD","utils.buildStates","comments.ensureComment","comments.ensureCommentRemoval"],"sources":["../../../../lib/modules/platform/bitbucket/index.ts"],"sourcesContent":["import { isNonEmptyArray, isNonEmptyString } from '@sindresorhus/is';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { REPOSITORY_NOT_FOUND } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport type { BranchStatus } from '../../../types/index.ts';\nimport { getInheritedOrGlobal, parseJson } from '../../../util/common.ts';\nimport * as git from '../../../util/git/index.ts';\nimport * as hostRules from '../../../util/host-rules.ts';\nimport type { BitbucketHttpOptions } from '../../../util/http/bitbucket.ts';\nimport { BitbucketHttp, setBaseUrl } from '../../../util/http/bitbucket.ts';\nimport { memCacheProvider } from '../../../util/http/cache/memory-http-cache-provider.ts';\nimport {\n aggressiveRepoCacheProvider,\n repoCacheProvider,\n} from '../../../util/http/cache/repository-http-cache-provider.ts';\nimport type { HttpOptions } from '../../../util/http/types.ts';\nimport * as promises from '../../../util/promises.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { sanitize } from '../../../util/sanitize.ts';\nimport { UUIDRegex, matchRegexOrGlobList } from '../../../util/string-match.ts';\nimport { parseUrl } from '../../../util/url.ts';\nimport type {\n AutodiscoverConfig,\n BranchStatusConfig,\n CreatePRConfig,\n EnsureCommentConfig,\n EnsureCommentRemovalConfig,\n EnsureIssueConfig,\n EnsureIssueResult,\n FindPRConfig,\n Issue,\n MergePRConfig,\n PlatformParams,\n PlatformResult,\n Pr,\n RepoParams,\n RepoResult,\n UpdatePrConfig,\n} from '../types.ts';\nimport { repoFingerprint } from '../util.ts';\nimport { smartTruncate } from '../utils/pr-body.ts';\nimport { readOnlyIssueBody } from '../utils/read-only-issue-body.ts';\nimport * as comments from './comments.ts';\nimport { BitbucketPrCache } from './pr-cache.ts';\nimport {\n RepoInfo,\n Repositories,\n UnresolvedPrTasks,\n WorkspaceAccesses,\n} from './schema.ts';\nimport type {\n Account,\n BitbucketStatus,\n BranchResponse,\n Config,\n EffectiveReviewer,\n PagedResult,\n PrResponse,\n RepoBranchingModel,\n} from './types.ts';\nimport * as utils from './utils.ts';\nimport { mergeBodyTransformer } from './utils.ts';\n\nexport const id = 'bitbucket';\n\nconst bitbucketHttp = new BitbucketHttp();\n\nconst BITBUCKET_PROD_ENDPOINT = 'https://api.bitbucket.org/';\n\nlet config: Config = {} as any;\n\nexport function resetPlatform(): void {\n config = {} as any;\n renovateUserUuid = null;\n}\n\nconst defaults = { endpoint: BITBUCKET_PROD_ENDPOINT };\n\nconst pathSeparator = '/';\n\nlet renovateUserUuid: string | null = null;\n\nexport async function initPlatform({\n endpoint,\n username,\n password,\n token,\n}: PlatformParams): Promise<PlatformResult> {\n if (!(username && password) && !token) {\n throw new Error(\n 'Init: You must configure either a Bitbucket token or username and password',\n );\n }\n if (endpoint && endpoint !== BITBUCKET_PROD_ENDPOINT) {\n logger.warn(\n `Init: Bitbucket Cloud endpoint should generally be ${BITBUCKET_PROD_ENDPOINT} but is being configured to a different value. Did you mean to use Bitbucket Server?`,\n );\n defaults.endpoint = endpoint;\n }\n setBaseUrl(defaults.endpoint);\n renovateUserUuid = null;\n const options: HttpOptions = { memCache: false };\n if (token) {\n options.token = token;\n } else {\n options.username = username;\n options.password = password;\n }\n try {\n const { uuid } = (\n await bitbucketHttp.getJsonUnchecked<Account>('/2.0/user', options)\n ).body;\n renovateUserUuid = uuid;\n } catch (err) {\n if (\n err.statusCode === 403 &&\n err.body?.error?.detail?.required?.includes('account')\n ) {\n logger.warn(`Bitbucket: missing 'account' scope for password`);\n } else {\n logger.debug({ err }, 'Unknown error fetching Bitbucket user identity');\n }\n }\n // TODO: Add a connection check that endpoint/username/password combination are valid (#9594)\n const platformConfig: PlatformResult = {\n endpoint: endpoint ?? BITBUCKET_PROD_ENDPOINT,\n };\n return Promise.resolve(platformConfig);\n}\n\n// Get all repositories that the user has access to\nexport async function getRepos(config: AutodiscoverConfig): Promise<string[]> {\n logger.debug('Autodiscovering Bitbucket Cloud repositories');\n try {\n // Determine which workspaces to query.\n // If the caller supplied explicit namespaces use them directly;\n // otherwise discover all workspaces the authenticated user belongs to.\n // The old cross-workspace endpoint GET /2.0/repositories?role=contributor\n // was removed by Bitbucket on 2026-03-31 (CHANGE-2770).\n let workspaceSlugs: string[];\n const autodiscoverNamespaces = config.namespaces;\n if (isNonEmptyArray(autodiscoverNamespaces)) {\n logger.debug(\n { autodiscoverNamespaces },\n 'Using configured namespaces as Bitbucket workspaces',\n );\n workspaceSlugs = autodiscoverNamespaces;\n } else {\n logger.debug('Fetching Bitbucket workspaces for the current user');\n const { body: slugs } = await bitbucketHttp.getJson(\n '/2.0/user/workspaces',\n { paginate: true },\n WorkspaceAccesses,\n );\n workspaceSlugs = slugs;\n logger.debug(\n { workspaceSlugs },\n `Found ${workspaceSlugs.length} Bitbucket workspace(s)`,\n );\n }\n\n // Fetch repositories for every workspace in parallel (concurrency-limited).\n const repoArrays = await promises.map(workspaceSlugs, (workspace) =>\n bitbucketHttp\n .getJson(\n `/2.0/repositories/${workspace}`,\n { paginate: true },\n Repositories,\n )\n .then(({ body }) => body),\n );\n\n let repos = repoArrays.flat();\n\n // if autodiscoverProjects is configured, filter the repos list\n const autodiscoverProjects = config.projects;\n if (isNonEmptyArray(autodiscoverProjects)) {\n logger.debug(\n { autodiscoverProjects: config.projects },\n 'Applying autodiscoverProjects filter',\n );\n repos = repos.filter(\n (repo) =>\n repo.projectName &&\n matchRegexOrGlobList(repo.projectName, autodiscoverProjects),\n );\n }\n\n return repos.map(({ owner, name }) => `${owner}/${name}`);\n } catch (err) /* v8 ignore next */ {\n logger.error({ err }, `bitbucket getRepos error`);\n throw err;\n }\n}\n\nexport async function getRawFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n): Promise<string | null> {\n // See: https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Bworkspace%7D/%7Brepo_slug%7D/src/%7Bcommit%7D/%7Bpath%7D\n const repo = repoName ?? config.repository;\n const path = fileName;\n\n let finalBranchOrTag = branchOrTag;\n if (branchOrTag?.includes(pathSeparator)) {\n // Branch name contains slash, so we have to replace branch name with SHA1 of the head commit; otherwise the API will not work.\n finalBranchOrTag = await getBranchCommit(branchOrTag);\n }\n\n const url = `/2.0/repositories/${repo}/src/${finalBranchOrTag ?? `HEAD`}/${path}`;\n const res = await bitbucketHttp.getText(url, {\n cacheProvider: repoCacheProvider,\n });\n return res.body;\n}\n\nexport async function getJsonFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n): Promise<any> {\n // TODO #22198\n const raw = await getRawFile(fileName, repoName, branchOrTag);\n return parseJson(raw, fileName);\n}\n\n// Initialize bitbucket by getting base branch and SHA\nexport async function initRepo({\n repository,\n cloneSubmodules,\n cloneSubmodulesFilter,\n}: RepoParams): Promise<RepoResult> {\n logger.debug(`initRepo(\"${repository}\")`);\n const opts = hostRules.find({\n hostType: 'bitbucket',\n url: defaults.endpoint,\n });\n config = {\n repository,\n ignorePrAuthor: GlobalConfig.get('ignorePrAuthor'),\n } as Config;\n let info: RepoInfo;\n let mainBranch: string;\n try {\n const { body: repoInfo } = await bitbucketHttp.getJson(\n `/2.0/repositories/${repository}`,\n RepoInfo,\n );\n info = repoInfo;\n\n mainBranch = info.mainbranch;\n\n if (getInheritedOrGlobal('bbUseDevelopmentBranch')) {\n // Fetch Bitbucket development branch\n const developmentBranch = (\n await bitbucketHttp.getJsonUnchecked<RepoBranchingModel>(\n `/2.0/repositories/${repository}/branching-model`,\n )\n ).body.development?.branch?.name;\n\n if (developmentBranch) {\n mainBranch = developmentBranch;\n }\n }\n\n config.defaultBranch = mainBranch;\n\n config = {\n ...config,\n owner: info.owner,\n mergeMethod: info.mergeMethod,\n has_issues: info.has_issues,\n is_private: info.is_private,\n };\n\n logger.debug(`${repository} owner = ${config.owner}`);\n } catch (err) /* v8 ignore next */ {\n if (err.statusCode === 404) {\n throw new Error(REPOSITORY_NOT_FOUND);\n }\n logger.debug({ err }, 'Unknown Bitbucket initRepo error');\n throw err;\n }\n\n const parsedEndpoint = parseUrl(defaults.endpoint);\n // v8 ignore if: endpoint is a constant\n if (!parsedEndpoint) {\n throw new Error(`Invalid Bitbucket endpoint: ${defaults.endpoint}`);\n }\n const { hostname } = parsedEndpoint;\n\n // Converts API hostnames to their respective HTTP git hosts:\n // `api.bitbucket.org` to `bitbucket.org`\n // `api-staging.<host>` to `staging.<host>`\n // TODO #22198\n const hostnameWithoutApiPrefix = regEx(/api[.|-](.+)/).exec(hostname)?.[1];\n\n let auth = '';\n if (opts.token) {\n auth = `x-token-auth:${opts.token}`;\n } else if (opts.password?.startsWith('ATAT')) {\n auth = `x-bitbucket-api-token-auth:${opts.password}`;\n } else {\n auth = `${opts.username!}:${opts.password!}`;\n }\n\n const url = git.getUrl({\n protocol: 'https',\n auth,\n hostname: hostnameWithoutApiPrefix,\n repository,\n });\n\n await git.initRepo({\n ...config,\n url,\n cloneSubmodules,\n cloneSubmodulesFilter,\n });\n const repoConfig: RepoResult = {\n defaultBranch: mainBranch,\n isFork: info.isFork,\n repoFingerprint: repoFingerprint(info.uuid, defaults.endpoint),\n };\n return repoConfig;\n}\n\n/* v8 ignore next */\nfunction matchesState(state: string, desiredState: string): boolean {\n if (desiredState === 'all') {\n return true;\n }\n if (desiredState.startsWith('!')) {\n return state !== desiredState.substring(1);\n }\n return state === desiredState;\n}\n\nexport async function getPrList(): Promise<Pr[]> {\n logger.trace('getPrList()');\n return await BitbucketPrCache.getPrs(\n bitbucketHttp,\n config.repository,\n renovateUserUuid,\n );\n}\n\nexport async function findPr({\n branchName,\n prTitle,\n state = 'all',\n includeOtherAuthors,\n}: FindPRConfig): Promise<Pr | null> {\n logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`);\n\n if (includeOtherAuthors) {\n // PR might have been created by anyone, so don't use the cached Renovate PR list\n const prs = (\n await bitbucketHttp.getJsonUnchecked<PagedResult<PrResponse>>(\n `/2.0/repositories/${config.repository}/pullrequests?q=source.branch.name=\"${branchName}\"&state=open`,\n { cacheProvider: memCacheProvider },\n )\n ).body.values;\n\n if (prs.length === 0) {\n logger.debug(`No PR found for branch ${branchName}`);\n return null;\n }\n\n return utils.prInfo(prs[0]);\n }\n\n const prList = await getPrList();\n const pr = prList.find(\n (p) =>\n p.sourceBranch === branchName &&\n (!prTitle || p.title.toUpperCase() === prTitle.toUpperCase()) &&\n matchesState(p.state, state),\n );\n\n if (!pr) {\n return null;\n }\n logger.debug(`Found PR #${pr.number}`);\n\n /**\n * Bitbucket doesn't support renaming or reopening declined PRs.\n * Instead, we have to use comment-driven signals.\n */\n if (pr.state === 'closed') {\n const reopenComments = await comments.reopenComments(config, pr.number);\n\n if (isNonEmptyArray(reopenComments)) {\n if (config.is_private) {\n // Only workspace members could have commented on a private repository\n logger.debug(\n `Found '${comments.REOPEN_PR_COMMENT_KEYWORD}' comment from workspace member. Renovate will reopen PR ${pr.number} as a new PR`,\n );\n return null;\n }\n\n for (const comment of reopenComments) {\n if (await isAccountMemberOfWorkspace(comment.user, config.repository)) {\n logger.debug(\n `Found '${comments.REOPEN_PR_COMMENT_KEYWORD}' comment from workspace member. Renovate will reopen PR ${pr.number} as a new PR`,\n );\n return null;\n }\n }\n }\n }\n\n return pr;\n}\n\n// Gets details for a PR\nexport async function getPr(prNo: number): Promise<Pr | null> {\n const pr = (\n await bitbucketHttp.getJsonUnchecked<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n )\n ).body;\n\n /* v8 ignore next */\n if (!pr) {\n return null;\n }\n\n const res: Pr = {\n ...utils.prInfo(pr),\n };\n\n if (isNonEmptyArray(pr.reviewers)) {\n res.reviewers = pr.reviewers\n .map(({ uuid }) => uuid)\n .filter(isNonEmptyString);\n }\n\n return res;\n}\n\nconst escapeHash = (input: string): string =>\n input?.replace(regEx(/#/g), '%23');\n\n// Return the commit SHA for a branch\nasync function getBranchCommit(\n branchName: string,\n): Promise<string | undefined> {\n try {\n const branch = (\n await bitbucketHttp.getJsonUnchecked<BranchResponse>(\n `/2.0/repositories/${config.repository}/refs/branches/${escapeHash(\n branchName,\n )}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n )\n ).body;\n return branch.target.hash;\n } catch (err) /* v8 ignore next */ {\n logger.debug({ err }, `getBranchCommit('${branchName}') failed'`);\n return undefined;\n }\n}\n\n// Returns the Pull Request for a branch. Null if not exists.\nexport async function getBranchPr(branchName: string): Promise<Pr | null> {\n logger.debug(`getBranchPr(${branchName})`);\n const existingPr = await findPr({\n branchName,\n state: 'open',\n });\n return existingPr ? getPr(existingPr.number) : null;\n}\n\nasync function getStatus(\n branchName: string,\n memCache = true,\n): Promise<BitbucketStatus[]> {\n const sha = await getBranchCommit(branchName);\n const opts: BitbucketHttpOptions = { paginate: true };\n /* v8 ignore next: temporary code */\n if (memCache) {\n opts.cacheProvider = aggressiveRepoCacheProvider;\n } else {\n opts.memCache = false;\n }\n return (\n await bitbucketHttp.getJsonUnchecked<PagedResult<BitbucketStatus>>(\n `/2.0/repositories/${config.repository}/commit/${sha!}/statuses`,\n opts,\n )\n ).body.values;\n}\n// Returns the combined status for a branch.\nexport async function getBranchStatus(\n branchName: string,\n internalChecksAsSuccess: boolean,\n): Promise<BranchStatus> {\n logger.debug(`getBranchStatus(${branchName})`);\n const statuses = await getStatus(branchName);\n logger.debug({ branch: branchName, statuses }, 'branch status check result');\n if (!statuses.length) {\n logger.debug('empty branch status check result = returning \"pending\"');\n return 'yellow';\n }\n const noOfFailures = statuses.filter(\n (status: { state: string }) =>\n status.state === 'FAILED' || status.state === 'STOPPED',\n ).length;\n if (noOfFailures) {\n return 'red';\n }\n const noOfPending = statuses.filter(\n (status: { state: string }) => status.state === 'INPROGRESS',\n ).length;\n if (noOfPending) {\n return 'yellow';\n }\n if (\n !internalChecksAsSuccess &&\n statuses.every(\n (status) =>\n status.state === 'SUCCESSFUL' && status.key?.startsWith('renovate/'),\n )\n ) {\n logger.debug(\n 'Successful checks are all internal renovate/ checks, so returning \"pending\" branch status',\n );\n return 'yellow';\n }\n return 'green';\n}\n\nconst bbToRenovateStatusMapping: Record<string, BranchStatus> = {\n SUCCESSFUL: 'green',\n INPROGRESS: 'yellow',\n FAILED: 'red',\n};\n\nexport async function getBranchStatusCheck(\n branchName: string,\n context: string,\n): Promise<BranchStatus | null> {\n const statuses = await getStatus(branchName);\n const bbState = statuses.find((status) => status.key === context)?.state;\n // TODO #22198\n return bbToRenovateStatusMapping[bbState!] || null;\n}\n\nexport async function setBranchStatus({\n branchName,\n context,\n description,\n state,\n url: targetUrl,\n}: BranchStatusConfig): Promise<void> {\n const sha = await getBranchCommit(branchName);\n\n // TargetUrl can not be empty so default to bitbucket\n /* v8 ignore next */\n const url = targetUrl ?? 'https://bitbucket.org';\n\n const body = {\n name: context,\n state: utils.buildStates[state],\n key: context,\n description,\n url,\n };\n\n await bitbucketHttp.postJson(\n `/2.0/repositories/${config.repository}/commit/${sha}/statuses/build`,\n { body },\n );\n\n // invalidate status cache\n const branchStatusesUrl = bitbucketHttp\n .resolveUrl(`/2.0/repositories/${config.repository}/commit/${sha}/statuses`)\n .toString();\n aggressiveRepoCacheProvider.markSynced('get', branchStatusesUrl, false);\n}\n\ninterface BbIssue {\n id: number;\n title: string;\n kind: string;\n content?: { raw: string };\n}\n\nasync function findOpenIssues(title: string): Promise<BbIssue[]> {\n try {\n const filters = [\n `title=${JSON.stringify(title)}`,\n '(state = \"new\" OR state = \"open\")',\n ];\n if (renovateUserUuid) {\n filters.push(`reporter.uuid=\"${renovateUserUuid}\"`);\n }\n const filter = encodeURIComponent(filters.join(' AND '));\n // v8 ignore next -- TODO: add test #40625\n return (\n (\n await bitbucketHttp.getJsonUnchecked<{ values: BbIssue[] }>(\n `/2.0/repositories/${config.repository}/issues?q=${filter}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n )\n ).body.values || []\n );\n } catch (err) /* v8 ignore next */ {\n logger.warn({ err }, 'Error finding issues');\n return [];\n }\n}\n\nexport async function findIssue(title: string): Promise<Issue | null> {\n logger.debug(`findIssue(${title})`);\n\n /* v8 ignore next */\n if (!config.has_issues) {\n logger.debug('Issues are disabled - cannot findIssue');\n return null;\n }\n const issues = await findOpenIssues(title);\n if (!issues.length) {\n return null;\n }\n const [issue] = issues;\n return {\n number: issue.id,\n body: issue.content?.raw,\n };\n}\n\nasync function closeIssue(issueNumber: number): Promise<void> {\n await bitbucketHttp.putJson(\n `/2.0/repositories/${config.repository}/issues/${issueNumber}`,\n {\n body: { state: 'closed' },\n },\n );\n}\n\n/**\n * Remove or transform markdown into Bitbucket supported syntax.\n *\n * See https://bitbucket.org/tutorials/markdowndemo/src for supported markdown syntax\n */\n/**\n * Remove or transform markdown into Bitbucket supported syntax.\n *\n * See https://bitbucket.org/tutorials/markdowndemo/src for supported markdown syntax\n */\nexport function massageMarkdown(input: string): string {\n let massaged = smartTruncate(input, maxBodyLength())\n .replace(\n 'you tick the rebase/retry checkbox',\n 'by renaming this PR to start with \"rebase!\"',\n )\n .replace(\n 'checking the rebase/retry box above',\n 'renaming the PR to start with \"rebase!\"',\n )\n .replace(\n regEx(\n /<details>\\n(<summary>View abandoned dependencies.*<\\/summary>\\n\\n)([\\s\\S]*?)<\\/details>/,\n ),\n '$2',\n )\n .replace(regEx(`\\n---\\n\\n.*?<!-- rebase-check -->.*?\\n`), '')\n .replace(regEx(/\\]\\(\\.\\.\\/issues\\//g), '](../../issues/')\n .replace(regEx(/\\]\\(\\.\\.\\/pull\\//g), '](../../pull-requests/')\n .replace(regEx(/<!--renovate-(?:debug|config-hash):.*?-->/g), '');\n\n massaged = massageDetailSummaryHtmlToNestedLists(massaged);\n\n return massageCodeblockMarkdown(massaged);\n}\n\n/**\n * Massage codeblocks indentation to ensure correct rendering in Bitbucket.\n */\nfunction massageCodeblockMarkdown(body: string): string {\n const codeBlockRegex = regEx(\n /^(?<indent>[ \\t]*)```(?<lang>\\w*)[^\\n]*\\n(?<code>[\\s\\S]*?)\\n[ \\t]*```/gm,\n );\n let codeMatch;\n let result = body;\n\n while ((codeMatch = codeBlockRegex.exec(body)) !== null) {\n const { indent, lang, code } = codeMatch.groups!;\n const indentLength = indent.length;\n const lines = code.split('\\n');\n const cleanedLines = lines.map((line) =>\n // Remove `indentLength` characters from the start of each line\n line.slice(indentLength),\n );\n\n const cleaned = cleanedLines.join('\\n');\n const replacement = `\\`\\`\\`${lang}\\n${cleaned}\\n\\`\\`\\``;\n\n result = result.replace(codeMatch[0], replacement);\n }\n\n return result;\n}\n\n/**\n * Massage collapsible html sections into nested unordered lists.\n *\n * Bitbucket doesn't currently support collapsible syntax; https://jira.atlassian.com/browse/BCLOUD-20231\n */\nfunction massageDetailSummaryHtmlToNestedLists(body: string): string {\n let depth = 0;\n // Parse detail parts to calculate correct list depth\n const detailsParts = body.split('<details>').map((raw) => {\n const partDepth = depth;\n\n depth += 1;\n const countClosingDetailsTags = raw.split('</details>').length - 1;\n depth = Math.max(0, depth - countClosingDetailsTags);\n\n return { raw, partDepth };\n });\n\n // Reassemble parts while replacing collapsible html elements with markdown list\n return detailsParts\n .map(({ raw, partDepth }) => {\n let t = raw;\n\n if (partDepth === 0) {\n return t;\n }\n\n const partIndentation = '\\t'.repeat(partDepth - 1);\n const nestedListItemIndentation = '\\t'.repeat(partDepth);\n\n const rawContainsBlockquote = raw.includes('<blockquote>');\n\n t = t.replace(regEx(/<\\/?summary>/g), partDepth === 1 ? '**' : '`');\n\n if (partDepth > 1) {\n t = t.replace(\n regEx(/^([ \\t]*- [`[])/gm),\n `${nestedListItemIndentation}$1`,\n );\n }\n\n let result = partIndentation;\n if (rawContainsBlockquote || partDepth > 1) {\n result += ' - ';\n }\n result += t;\n\n return result;\n })\n .join('')\n .replace(/<\\/?(summary|details|blockquote)>/g, '');\n}\n\nexport function maxBodyLength(): number {\n return 250000;\n}\n\nexport async function ensureIssue({\n title,\n reuseTitle,\n body,\n}: EnsureIssueConfig): Promise<EnsureIssueResult | null> {\n logger.debug(`ensureIssue()`);\n /* v8 ignore next */\n if (!config.has_issues) {\n logger.debug('Issues are disabled - cannot ensureIssue');\n logger.debug(`Failed to ensure Issue with title:${title}`);\n return null;\n }\n try {\n let issues = await findOpenIssues(title);\n const description = massageMarkdown(sanitize(body));\n const issueKind = 'task';\n\n if (!issues.length && reuseTitle) {\n issues = await findOpenIssues(reuseTitle);\n }\n if (issues.length) {\n // Close any duplicates\n for (const issue of issues.slice(1)) {\n await closeIssue(issue.id);\n }\n const [issue] = issues;\n\n if (\n issue.title !== title ||\n String(issue.content?.raw).trim() !== description.trim() ||\n issue.kind !== issueKind\n ) {\n logger.debug('Issue updated');\n await bitbucketHttp.putJson(\n `/2.0/repositories/${config.repository}/issues/${issue.id}`,\n {\n body: {\n kind: issueKind,\n content: {\n raw: readOnlyIssueBody(description),\n markup: 'markdown',\n },\n },\n },\n );\n return 'updated';\n }\n } else {\n logger.info('Issue created');\n await bitbucketHttp.postJson(\n `/2.0/repositories/${config.repository}/issues`,\n {\n body: {\n title,\n kind: issueKind,\n content: {\n raw: readOnlyIssueBody(description),\n markup: 'markdown',\n },\n },\n },\n );\n return 'created';\n }\n } catch (err) /* v8 ignore next */ {\n if (err.message.startsWith('Repository has no issue tracker.')) {\n logger.debug(`Issues are disabled, so could not create issue: ${title}`);\n } else {\n logger.warn({ err }, 'Could not ensure issue');\n }\n }\n return null;\n}\n\n/* v8 ignore next */\nexport async function getIssueList(): Promise<Issue[]> {\n logger.debug(`getIssueList()`);\n\n if (!config.has_issues) {\n logger.debug('Issues are disabled - cannot getIssueList');\n return [];\n }\n try {\n const filters = ['(state = \"new\" OR state = \"open\")'];\n if (renovateUserUuid) {\n filters.push(`reporter.uuid=\"${renovateUserUuid}\"`);\n }\n const filter = encodeURIComponent(filters.join(' AND '));\n const url = `/2.0/repositories/${config.repository}/issues?q=${filter}`;\n const res = await bitbucketHttp.getJsonUnchecked<{ values: Issue[] }>(url, {\n cacheProvider: repoCacheProvider,\n });\n return res.body.values || [];\n } catch (err) {\n logger.warn({ err }, 'Error finding issues');\n return [];\n }\n}\n\nexport async function ensureIssueClosing(title: string): Promise<void> {\n /* v8 ignore next */\n if (!config.has_issues) {\n logger.debug('Issues are disabled - cannot ensureIssueClosing');\n return;\n }\n const issues = await findOpenIssues(title);\n for (const issue of issues) {\n await closeIssue(issue.id);\n }\n}\n\nexport function addAssignees(\n _prNr: number,\n _assignees: string[],\n): Promise<void> {\n // Bitbucket supports \"participants\" and \"reviewers\" so does not seem to have the concept of \"assignee\"\n logger.warn('Cannot add assignees');\n return Promise.resolve();\n}\n\nexport async function addReviewers(\n prId: number,\n reviewers: string[],\n): Promise<void> {\n logger.debug(`Adding reviewers '${reviewers.join(', ')}' to #${prId}`);\n\n // TODO #22198\n const { title } = (await getPr(prId))!;\n\n const body = {\n title,\n reviewers: reviewers.map((username: string) => {\n const isUUID =\n username.startsWith('{') &&\n username.endsWith('}') &&\n UUIDRegex.test(username.slice(1, -1));\n const key = isUUID ? 'uuid' : 'username';\n return {\n [key]: username,\n };\n }),\n };\n\n await bitbucketHttp.putJson(\n `/2.0/repositories/${config.repository}/pullrequests/${prId}`,\n {\n body,\n },\n );\n}\n\n/* v8 ignore next */\nexport function deleteLabel(): never {\n throw new Error('deleteLabel not implemented');\n}\n\nexport function ensureComment({\n number,\n topic,\n content,\n}: EnsureCommentConfig): Promise<boolean> {\n // https://developer.atlassian.com/bitbucket/api/2/reference/search?q=pullrequest+comment\n return comments.ensureComment({\n config,\n number,\n topic,\n content: sanitize(content),\n });\n}\n\nexport function ensureCommentRemoval(\n deleteConfig: EnsureCommentRemovalConfig,\n): Promise<void> {\n return comments.ensureCommentRemoval(config, deleteConfig);\n}\n\nasync function sanitizeReviewers(\n reviewers: Account[],\n err: any,\n): Promise<Account[] | undefined> {\n if (err.statusCode === 400 && err.body?.error?.fields?.reviewers) {\n const sanitizedReviewers: Account[] = [];\n\n const MSG_AUTHOR_AND_REVIEWER =\n 'is the author and cannot be included as a reviewer.';\n const MSG_MALFORMED_REVIEWERS_LIST = 'Malformed reviewers list';\n const MSG_NOT_WORKSPACE_MEMBER =\n 'is not a member of this workspace and cannot be added to this pull request';\n\n for (const msg of err.body.error.fields.reviewers) {\n // Bitbucket returns a 400 if any of the PR reviewer accounts are now inactive (ie: disabled/suspended)\n if (msg === MSG_MALFORMED_REVIEWERS_LIST) {\n logger.debug(\n { err },\n 'PR contains reviewers that may be either inactive or no longer a member of this workspace. Will try setting only active reviewers',\n );\n\n // Validate that each previous PR reviewer account is still active\n for (const reviewer of reviewers) {\n const reviewerUser = (\n await bitbucketHttp.getJsonUnchecked<Account>(\n `/2.0/users/${reviewer.uuid}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n )\n ).body;\n\n // There are cases where an active user may still not be a member of a workspace\n if (\n reviewerUser.account_status === 'active' &&\n (await isAccountMemberOfWorkspace(reviewer, config.repository))\n ) {\n sanitizedReviewers.push(reviewer);\n }\n }\n // Bitbucket returns a 400 if any of the PR reviewer accounts are no longer members of this workspace\n } else if (msg.endsWith(MSG_NOT_WORKSPACE_MEMBER)) {\n logger.debug(\n { err },\n 'PR contains reviewer accounts which are no longer member of this workspace. Will try setting only member reviewers',\n );\n\n // Validate that each previous PR reviewer account is still a member of this workspace\n for (const reviewer of reviewers) {\n if (await isAccountMemberOfWorkspace(reviewer, config.repository)) {\n sanitizedReviewers.push(reviewer);\n }\n }\n } else if (msg.endsWith(MSG_AUTHOR_AND_REVIEWER)) {\n logger.debug(\n { err },\n 'PR contains reviewer accounts which are also the author. Will try setting only non-author reviewers',\n );\n const author = msg.replace(MSG_AUTHOR_AND_REVIEWER, '').trim();\n for (const reviewer of reviewers) {\n if (reviewer.display_name !== author) {\n sanitizedReviewers.push(reviewer);\n }\n }\n } else {\n return undefined;\n }\n }\n\n return sanitizedReviewers;\n }\n\n return undefined;\n}\n\nasync function isAccountMemberOfWorkspace(\n reviewer: Account,\n repository: string,\n): Promise<boolean> {\n const workspace = repository.split('/')[0];\n\n try {\n await bitbucketHttp.get(\n `/2.0/workspaces/${workspace}/members/${reviewer.uuid}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n );\n\n return true;\n } catch (err) {\n // HTTP 404: User cannot be found, or the user is not a member of this workspace.\n if (err.statusCode === 404) {\n logger.debug(\n { err },\n `User ${reviewer.display_name} is not a member of the workspace ${workspace}. Will be removed from the PR`,\n );\n\n return false;\n }\n throw err;\n }\n}\n\n// Creates PR and returns PR number\nexport async function createPr({\n sourceBranch,\n targetBranch,\n prTitle: title,\n prBody: description,\n draftPR = false,\n platformPrOptions,\n}: CreatePRConfig): Promise<Pr> {\n // labels is not supported in Bitbucket: https://bitbucket.org/site/master/issues/11976/ability-to-add-labels-to-pull-requests-bb\n\n const base = targetBranch;\n\n logger.debug({ repository: config.repository, title, base }, 'Creating PR');\n\n let reviewers: Account[] = [];\n\n if (platformPrOptions?.bbUseDefaultReviewers) {\n const reviewersResponse = (\n await bitbucketHttp.getJsonUnchecked<PagedResult<EffectiveReviewer>>(\n `/2.0/repositories/${config.repository}/effective-default-reviewers`,\n {\n paginate: true,\n cacheProvider: aggressiveRepoCacheProvider,\n },\n )\n ).body;\n reviewers = reviewersResponse.values.map((reviewer: EffectiveReviewer) => ({\n uuid: reviewer.user.uuid,\n display_name: reviewer.user.display_name,\n }));\n }\n\n const body = {\n title,\n description: sanitize(description),\n source: {\n branch: {\n name: sourceBranch,\n },\n },\n destination: {\n branch: {\n name: base,\n },\n },\n close_source_branch: true,\n reviewers,\n draft: draftPR,\n };\n\n try {\n const prRes = (\n await bitbucketHttp.postJson<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests`,\n {\n body,\n },\n )\n ).body;\n const pr = utils.prInfo(prRes);\n await BitbucketPrCache.setPr(\n bitbucketHttp,\n config.repository,\n renovateUserUuid,\n pr,\n );\n if (platformPrOptions?.bbAutoResolvePrTasks) {\n await autoResolvePrTasks(pr);\n }\n return pr;\n } catch (err) /* v8 ignore next */ {\n // Try sanitizing reviewers\n const sanitizedReviewers = await sanitizeReviewers(reviewers, err);\n\n if (sanitizedReviewers === undefined) {\n logger.warn({ err }, 'Error creating pull request');\n throw err;\n } else {\n const prRes = (\n await bitbucketHttp.postJson<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests`,\n {\n body: {\n ...body,\n reviewers: sanitizedReviewers,\n },\n },\n )\n ).body;\n const pr = utils.prInfo(prRes);\n await BitbucketPrCache.setPr(\n bitbucketHttp,\n config.repository,\n renovateUserUuid,\n pr,\n );\n if (platformPrOptions?.bbAutoResolvePrTasks) {\n await autoResolvePrTasks(pr);\n }\n return pr;\n }\n }\n}\n\nasync function autoResolvePrTasks(pr: Pr): Promise<void> {\n logger.debug(`Auto resolve PR tasks in #${pr.number}`);\n try {\n const unResolvedTasks = (\n await bitbucketHttp.getJson(\n `/2.0/repositories/${config.repository}/pullrequests/${pr.number}/tasks`,\n { paginate: true, pagelen: 100 },\n UnresolvedPrTasks,\n )\n ).body;\n\n logger.trace(\n {\n prId: pr.number,\n listTaskRes: unResolvedTasks,\n },\n 'List PR tasks',\n );\n\n for (const task of unResolvedTasks) {\n const res = await bitbucketHttp.putJson(\n `/2.0/repositories/${config.repository}/pullrequests/${pr.number}/tasks/${task.id}`,\n {\n body: {\n state: 'RESOLVED',\n content: {\n raw: task.content.raw,\n },\n },\n },\n );\n logger.trace(\n {\n prId: pr.number,\n updateTaskResponse: res,\n },\n 'Put PR tasks - mark resolved',\n );\n }\n } catch (err) {\n logger.warn({ prId: pr.number, err }, 'Error resolving PR tasks');\n }\n}\n\nexport async function updatePr({\n number: prNo,\n prTitle: title,\n prBody: description,\n state,\n targetBranch,\n}: UpdatePrConfig): Promise<void> {\n logger.debug(`updatePr(${prNo}, ${title}, body)`);\n // Updating a PR in Bitbucket will clear the reviewers if reviewers is not present\n const pr = (\n await bitbucketHttp.getJsonUnchecked<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,\n )\n ).body;\n\n let updatedPrRes: PrResponse;\n try {\n const body: any = {\n title,\n description: sanitize(description),\n reviewers: pr.reviewers,\n };\n if (targetBranch) {\n body.destination = {\n branch: {\n name: targetBranch,\n },\n };\n }\n\n updatedPrRes = (\n await bitbucketHttp.putJson<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,\n { body },\n )\n ).body;\n } catch (err) {\n // Try sanitizing reviewers\n const sanitizedReviewers = await sanitizeReviewers(pr.reviewers, err);\n\n if (sanitizedReviewers === undefined) {\n throw err;\n } else {\n updatedPrRes = (\n await bitbucketHttp.putJson<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,\n {\n body: {\n title,\n description: sanitize(description),\n reviewers: sanitizedReviewers,\n },\n },\n )\n ).body;\n }\n }\n\n if (state === 'closed' && pr) {\n await bitbucketHttp.postJson(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}/decline`,\n );\n }\n\n // update pr cache\n await BitbucketPrCache.setPr(\n bitbucketHttp,\n config.repository,\n renovateUserUuid,\n utils.prInfo({ ...updatedPrRes, ...(state && { state }) }),\n );\n}\n\nexport async function mergePr({\n branchName,\n id: prNo,\n strategy: mergeStrategy,\n}: MergePRConfig): Promise<boolean> {\n logger.debug(`mergePr(${prNo}, ${branchName}, ${mergeStrategy})`);\n\n // Bitbucket Cloud does not support a rebase-alike; https://jira.atlassian.com/browse/BCLOUD-16610\n if (mergeStrategy === 'rebase') {\n logger.warn('Bitbucket Cloud does not support a \"rebase\" strategy.');\n return false;\n }\n\n try {\n await bitbucketHttp.postJson(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}/merge`,\n {\n body: mergeBodyTransformer(mergeStrategy),\n },\n );\n logger.debug('Automerging succeeded');\n } catch (err) /* v8 ignore next */ {\n logger.debug({ err }, `PR merge error`);\n logger.info({ pr: prNo }, 'PR automerge failed');\n return false;\n }\n return true;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["promises.map","hostRules.find","git.getUrl","git.initRepo","utils.prInfo","reopenComments","comments.reopenComments","comments.REOPEN_PR_COMMENT_KEYWORD","utils.buildStates","comments.ensureComment","comments.ensureCommentRemoval"],"sources":["../../../../lib/modules/platform/bitbucket/index.ts"],"sourcesContent":["import { isNonEmptyArray, isNonEmptyString } from '@sindresorhus/is';\nimport { GlobalConfig } from '../../../config/global.ts';\nimport { REPOSITORY_NOT_FOUND } from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport type { BranchStatus } from '../../../types/index.ts';\nimport { getInheritedOrGlobal, parseJson } from '../../../util/common.ts';\nimport * as git from '../../../util/git/index.ts';\nimport * as hostRules from '../../../util/host-rules.ts';\nimport type { BitbucketHttpOptions } from '../../../util/http/bitbucket.ts';\nimport { BitbucketHttp, setBaseUrl } from '../../../util/http/bitbucket.ts';\nimport { memCacheProvider } from '../../../util/http/cache/memory-http-cache-provider.ts';\nimport {\n aggressiveRepoCacheProvider,\n repoCacheProvider,\n} from '../../../util/http/cache/repository-http-cache-provider.ts';\nimport type { HttpOptions } from '../../../util/http/types.ts';\nimport * as promises from '../../../util/promises.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { sanitize } from '../../../util/sanitize.ts';\nimport { UUIDRegex, matchRegexOrGlobList } from '../../../util/string-match.ts';\nimport { parseUrl } from '../../../util/url.ts';\nimport type {\n AutodiscoverConfig,\n BranchStatusConfig,\n CreatePRConfig,\n EnsureCommentConfig,\n EnsureCommentRemovalConfig,\n EnsureIssueConfig,\n EnsureIssueResult,\n FindPRConfig,\n Issue,\n MergePRConfig,\n PlatformParams,\n PlatformResult,\n Pr,\n RepoParams,\n RepoResult,\n UpdatePrConfig,\n} from '../types.ts';\nimport { repoFingerprint } from '../util.ts';\nimport { smartTruncate } from '../utils/pr-body.ts';\nimport { readOnlyIssueBody } from '../utils/read-only-issue-body.ts';\nimport * as comments from './comments.ts';\nimport { BitbucketPrCache } from './pr-cache.ts';\nimport {\n RepoInfo,\n Repositories,\n UnresolvedPrTasks,\n WorkspaceAccesses,\n} from './schema.ts';\nimport type {\n Account,\n BitbucketStatus,\n BranchResponse,\n Config,\n EffectiveReviewer,\n PagedResult,\n PrResponse,\n RepoBranchingModel,\n} from './types.ts';\nimport * as utils from './utils.ts';\nimport { mergeBodyTransformer } from './utils.ts';\n\nexport const id = 'bitbucket';\n\nconst bitbucketHttp = new BitbucketHttp();\n\nconst BITBUCKET_PROD_ENDPOINT = 'https://api.bitbucket.org/';\n\nlet config: Config = {} as any;\n\nexport function resetPlatform(): void {\n config = {} as any;\n renovateUserUuid = null;\n}\n\nconst defaults = { endpoint: BITBUCKET_PROD_ENDPOINT };\n\nconst pathSeparator = '/';\n\nlet renovateUserUuid: string | null = null;\n\nexport async function initPlatform({\n endpoint,\n username,\n password,\n token,\n}: PlatformParams): Promise<PlatformResult> {\n if (!(username && password) && !token) {\n throw new Error(\n 'Init: You must configure either a Bitbucket token or username and password',\n );\n }\n if (endpoint && endpoint !== BITBUCKET_PROD_ENDPOINT) {\n logger.warn(\n { endpoint, defaultEndpoint: BITBUCKET_PROD_ENDPOINT },\n 'Init: Bitbucket Cloud endpoint should generally be the default but is being configured to a different value. Did you mean to use Bitbucket Server?',\n );\n defaults.endpoint = endpoint;\n }\n setBaseUrl(defaults.endpoint);\n renovateUserUuid = null;\n const options: HttpOptions = { memCache: false };\n if (token) {\n options.token = token;\n } else {\n options.username = username;\n options.password = password;\n }\n try {\n const { uuid } = (\n await bitbucketHttp.getJsonUnchecked<Account>('/2.0/user', options)\n ).body;\n renovateUserUuid = uuid;\n } catch (err) {\n if (\n err.statusCode === 403 &&\n err.body?.error?.detail?.required?.includes('account')\n ) {\n logger.warn(`Bitbucket: missing 'account' scope for password`);\n } else {\n logger.debug({ err }, 'Unknown error fetching Bitbucket user identity');\n }\n }\n // TODO: Add a connection check that endpoint/username/password combination are valid (#9594)\n const platformConfig: PlatformResult = {\n endpoint: endpoint ?? BITBUCKET_PROD_ENDPOINT,\n };\n return Promise.resolve(platformConfig);\n}\n\n// Get all repositories that the user has access to\nexport async function getRepos(config: AutodiscoverConfig): Promise<string[]> {\n logger.debug('Autodiscovering Bitbucket Cloud repositories');\n try {\n // Determine which workspaces to query.\n // If the caller supplied explicit namespaces use them directly;\n // otherwise discover all workspaces the authenticated user belongs to.\n // The old cross-workspace endpoint GET /2.0/repositories?role=contributor\n // was removed by Bitbucket on 2026-03-31 (CHANGE-2770).\n let workspaceSlugs: string[];\n const autodiscoverNamespaces = config.namespaces;\n if (isNonEmptyArray(autodiscoverNamespaces)) {\n logger.debug(\n { autodiscoverNamespaces },\n 'Using configured namespaces as Bitbucket workspaces',\n );\n workspaceSlugs = autodiscoverNamespaces;\n } else {\n logger.debug('Fetching Bitbucket workspaces for the current user');\n const { body: slugs } = await bitbucketHttp.getJson(\n '/2.0/user/workspaces',\n { paginate: true },\n WorkspaceAccesses,\n );\n workspaceSlugs = slugs;\n logger.debug(\n { workspaceSlugs },\n `Found ${workspaceSlugs.length} Bitbucket workspace(s)`,\n );\n }\n\n // Fetch repositories for every workspace in parallel (concurrency-limited).\n const repoArrays = await promises.map(workspaceSlugs, (workspace) =>\n bitbucketHttp\n .getJson(\n `/2.0/repositories/${workspace}`,\n { paginate: true },\n Repositories,\n )\n .then(({ body }) => body),\n );\n\n let repos = repoArrays.flat();\n\n // if autodiscoverProjects is configured, filter the repos list\n const autodiscoverProjects = config.projects;\n if (isNonEmptyArray(autodiscoverProjects)) {\n logger.debug(\n { autodiscoverProjects: config.projects },\n 'Applying autodiscoverProjects filter',\n );\n repos = repos.filter(\n (repo) =>\n repo.projectName &&\n matchRegexOrGlobList(repo.projectName, autodiscoverProjects),\n );\n }\n\n return repos.map(({ owner, name }) => `${owner}/${name}`);\n } catch (err) /* v8 ignore next */ {\n logger.error({ err }, `bitbucket getRepos error`);\n throw err;\n }\n}\n\nexport async function getRawFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n): Promise<string | null> {\n // See: https://developer.atlassian.com/bitbucket/api/2/reference/resource/repositories/%7Bworkspace%7D/%7Brepo_slug%7D/src/%7Bcommit%7D/%7Bpath%7D\n const repo = repoName ?? config.repository;\n const path = fileName;\n\n let finalBranchOrTag = branchOrTag;\n if (branchOrTag?.includes(pathSeparator)) {\n // Branch name contains slash, so we have to replace branch name with SHA1 of the head commit; otherwise the API will not work.\n finalBranchOrTag = await getBranchCommit(branchOrTag);\n }\n\n const url = `/2.0/repositories/${repo}/src/${finalBranchOrTag ?? `HEAD`}/${path}`;\n const res = await bitbucketHttp.getText(url, {\n cacheProvider: repoCacheProvider,\n });\n return res.body;\n}\n\nexport async function getJsonFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n): Promise<any> {\n // TODO #22198\n const raw = await getRawFile(fileName, repoName, branchOrTag);\n return parseJson(raw, fileName);\n}\n\n// Initialize bitbucket by getting base branch and SHA\nexport async function initRepo({\n repository,\n cloneSubmodules,\n cloneSubmodulesFilter,\n}: RepoParams): Promise<RepoResult> {\n logger.debug(`initRepo(\"${repository}\")`);\n const opts = hostRules.find({\n hostType: 'bitbucket',\n url: defaults.endpoint,\n });\n config = {\n repository,\n ignorePrAuthor: GlobalConfig.get('ignorePrAuthor'),\n } as Config;\n let info: RepoInfo;\n let mainBranch: string;\n try {\n const { body: repoInfo } = await bitbucketHttp.getJson(\n `/2.0/repositories/${repository}`,\n RepoInfo,\n );\n info = repoInfo;\n\n mainBranch = info.mainbranch;\n\n if (getInheritedOrGlobal('bbUseDevelopmentBranch')) {\n // Fetch Bitbucket development branch\n const developmentBranch = (\n await bitbucketHttp.getJsonUnchecked<RepoBranchingModel>(\n `/2.0/repositories/${repository}/branching-model`,\n )\n ).body.development?.branch?.name;\n\n if (developmentBranch) {\n mainBranch = developmentBranch;\n }\n }\n\n config.defaultBranch = mainBranch;\n\n config = {\n ...config,\n owner: info.owner,\n mergeMethod: info.mergeMethod,\n has_issues: info.has_issues,\n is_private: info.is_private,\n };\n\n logger.debug(`${repository} owner = ${config.owner}`);\n } catch (err) /* v8 ignore next */ {\n if (err.statusCode === 404) {\n throw new Error(REPOSITORY_NOT_FOUND);\n }\n logger.debug({ err }, 'Unknown Bitbucket initRepo error');\n throw err;\n }\n\n const parsedEndpoint = parseUrl(defaults.endpoint);\n // v8 ignore if: endpoint is a constant\n if (!parsedEndpoint) {\n throw new Error(`Invalid Bitbucket endpoint: ${defaults.endpoint}`);\n }\n const { hostname } = parsedEndpoint;\n\n // Converts API hostnames to their respective HTTP git hosts:\n // `api.bitbucket.org` to `bitbucket.org`\n // `api-staging.<host>` to `staging.<host>`\n // TODO #22198\n const hostnameWithoutApiPrefix = regEx(/api[.|-](.+)/).exec(hostname)?.[1];\n\n let auth = '';\n if (opts.token) {\n auth = `x-token-auth:${opts.token}`;\n } else if (opts.password?.startsWith('ATAT')) {\n auth = `x-bitbucket-api-token-auth:${opts.password}`;\n } else {\n auth = `${opts.username!}:${opts.password!}`;\n }\n\n const url = git.getUrl({\n protocol: 'https',\n auth,\n hostname: hostnameWithoutApiPrefix,\n repository,\n });\n\n await git.initRepo({\n ...config,\n url,\n cloneSubmodules,\n cloneSubmodulesFilter,\n });\n const repoConfig: RepoResult = {\n defaultBranch: mainBranch,\n isFork: info.isFork,\n repoFingerprint: repoFingerprint(info.uuid, defaults.endpoint),\n };\n return repoConfig;\n}\n\n/* v8 ignore next */\nfunction matchesState(state: string, desiredState: string): boolean {\n if (desiredState === 'all') {\n return true;\n }\n if (desiredState.startsWith('!')) {\n return state !== desiredState.substring(1);\n }\n return state === desiredState;\n}\n\nexport async function getPrList(): Promise<Pr[]> {\n logger.trace('getPrList()');\n return await BitbucketPrCache.getPrs(\n bitbucketHttp,\n config.repository,\n renovateUserUuid,\n );\n}\n\nexport async function findPr({\n branchName,\n prTitle,\n state = 'all',\n includeOtherAuthors,\n}: FindPRConfig): Promise<Pr | null> {\n logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`);\n\n if (includeOtherAuthors) {\n // PR might have been created by anyone, so don't use the cached Renovate PR list\n const prs = (\n await bitbucketHttp.getJsonUnchecked<PagedResult<PrResponse>>(\n `/2.0/repositories/${config.repository}/pullrequests?q=source.branch.name=\"${branchName}\"&state=open`,\n { cacheProvider: memCacheProvider },\n )\n ).body.values;\n\n if (prs.length === 0) {\n logger.debug(`No PR found for branch ${branchName}`);\n return null;\n }\n\n return utils.prInfo(prs[0]);\n }\n\n const prList = await getPrList();\n const pr = prList.find(\n (p) =>\n p.sourceBranch === branchName &&\n (!prTitle || p.title.toUpperCase() === prTitle.toUpperCase()) &&\n matchesState(p.state, state),\n );\n\n if (!pr) {\n return null;\n }\n logger.debug(`Found PR #${pr.number}`);\n\n /**\n * Bitbucket doesn't support renaming or reopening declined PRs.\n * Instead, we have to use comment-driven signals.\n */\n if (pr.state === 'closed') {\n const reopenComments = await comments.reopenComments(config, pr.number);\n\n if (isNonEmptyArray(reopenComments)) {\n if (config.is_private) {\n // Only workspace members could have commented on a private repository\n logger.debug(\n `Found '${comments.REOPEN_PR_COMMENT_KEYWORD}' comment from workspace member. Renovate will reopen PR ${pr.number} as a new PR`,\n );\n return null;\n }\n\n for (const comment of reopenComments) {\n if (await isAccountMemberOfWorkspace(comment.user, config.repository)) {\n logger.debug(\n `Found '${comments.REOPEN_PR_COMMENT_KEYWORD}' comment from workspace member. Renovate will reopen PR ${pr.number} as a new PR`,\n );\n return null;\n }\n }\n }\n }\n\n return pr;\n}\n\n// Gets details for a PR\nexport async function getPr(prNo: number): Promise<Pr | null> {\n const pr = (\n await bitbucketHttp.getJsonUnchecked<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n )\n ).body;\n\n /* v8 ignore next */\n if (!pr) {\n return null;\n }\n\n const res: Pr = {\n ...utils.prInfo(pr),\n };\n\n if (isNonEmptyArray(pr.reviewers)) {\n res.reviewers = pr.reviewers\n .map(({ uuid }) => uuid)\n .filter(isNonEmptyString);\n }\n\n return res;\n}\n\nconst escapeHash = (input: string): string =>\n input?.replace(regEx(/#/g), '%23');\n\n// Return the commit SHA for a branch\nasync function getBranchCommit(\n branchName: string,\n): Promise<string | undefined> {\n try {\n const branch = (\n await bitbucketHttp.getJsonUnchecked<BranchResponse>(\n `/2.0/repositories/${config.repository}/refs/branches/${escapeHash(\n branchName,\n )}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n )\n ).body;\n return branch.target.hash;\n } catch (err) /* v8 ignore next */ {\n logger.debug({ err }, `getBranchCommit('${branchName}') failed'`);\n return undefined;\n }\n}\n\n// Returns the Pull Request for a branch. Null if not exists.\nexport async function getBranchPr(branchName: string): Promise<Pr | null> {\n logger.debug(`getBranchPr(${branchName})`);\n const existingPr = await findPr({\n branchName,\n state: 'open',\n });\n return existingPr ? getPr(existingPr.number) : null;\n}\n\nasync function getStatus(\n branchName: string,\n memCache = true,\n): Promise<BitbucketStatus[]> {\n const sha = await getBranchCommit(branchName);\n const opts: BitbucketHttpOptions = { paginate: true };\n /* v8 ignore next: temporary code */\n if (memCache) {\n opts.cacheProvider = aggressiveRepoCacheProvider;\n } else {\n opts.memCache = false;\n }\n return (\n await bitbucketHttp.getJsonUnchecked<PagedResult<BitbucketStatus>>(\n `/2.0/repositories/${config.repository}/commit/${sha!}/statuses`,\n opts,\n )\n ).body.values;\n}\n// Returns the combined status for a branch.\nexport async function getBranchStatus(\n branchName: string,\n internalChecksAsSuccess: boolean,\n): Promise<BranchStatus> {\n logger.debug(`getBranchStatus(${branchName})`);\n const statuses = await getStatus(branchName);\n logger.debug({ branch: branchName, statuses }, 'branch status check result');\n if (!statuses.length) {\n logger.debug('empty branch status check result = returning \"pending\"');\n return 'yellow';\n }\n const noOfFailures = statuses.filter(\n (status: { state: string }) =>\n status.state === 'FAILED' || status.state === 'STOPPED',\n ).length;\n if (noOfFailures) {\n return 'red';\n }\n const noOfPending = statuses.filter(\n (status: { state: string }) => status.state === 'INPROGRESS',\n ).length;\n if (noOfPending) {\n return 'yellow';\n }\n if (\n !internalChecksAsSuccess &&\n statuses.every(\n (status) =>\n status.state === 'SUCCESSFUL' && status.key?.startsWith('renovate/'),\n )\n ) {\n logger.debug(\n 'Successful checks are all internal renovate/ checks, so returning \"pending\" branch status',\n );\n return 'yellow';\n }\n return 'green';\n}\n\nconst bbToRenovateStatusMapping: Record<string, BranchStatus> = {\n SUCCESSFUL: 'green',\n INPROGRESS: 'yellow',\n FAILED: 'red',\n};\n\nexport async function getBranchStatusCheck(\n branchName: string,\n context: string,\n): Promise<BranchStatus | null> {\n const statuses = await getStatus(branchName);\n const bbState = statuses.find((status) => status.key === context)?.state;\n // TODO #22198\n return bbToRenovateStatusMapping[bbState!] || null;\n}\n\nexport async function setBranchStatus({\n branchName,\n context,\n description,\n state,\n url: targetUrl,\n}: BranchStatusConfig): Promise<void> {\n const sha = await getBranchCommit(branchName);\n\n // TargetUrl can not be empty so default to bitbucket\n /* v8 ignore next */\n const url = targetUrl ?? 'https://bitbucket.org';\n\n const body = {\n name: context,\n state: utils.buildStates[state],\n key: context,\n description,\n url,\n };\n\n await bitbucketHttp.postJson(\n `/2.0/repositories/${config.repository}/commit/${sha}/statuses/build`,\n { body },\n );\n\n // invalidate status cache\n const branchStatusesUrl = bitbucketHttp\n .resolveUrl(`/2.0/repositories/${config.repository}/commit/${sha}/statuses`)\n .toString();\n aggressiveRepoCacheProvider.markSynced('get', branchStatusesUrl, false);\n}\n\ninterface BbIssue {\n id: number;\n title: string;\n kind: string;\n content?: { raw: string };\n}\n\nasync function findOpenIssues(title: string): Promise<BbIssue[]> {\n try {\n const filters = [\n `title=${JSON.stringify(title)}`,\n '(state = \"new\" OR state = \"open\")',\n ];\n if (renovateUserUuid) {\n filters.push(`reporter.uuid=\"${renovateUserUuid}\"`);\n }\n const filter = encodeURIComponent(filters.join(' AND '));\n // v8 ignore next -- TODO: add test #40625\n return (\n (\n await bitbucketHttp.getJsonUnchecked<{ values: BbIssue[] }>(\n `/2.0/repositories/${config.repository}/issues?q=${filter}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n )\n ).body.values || []\n );\n } catch (err) /* v8 ignore next */ {\n logger.warn({ err }, 'Error finding issues');\n return [];\n }\n}\n\nexport async function findIssue(title: string): Promise<Issue | null> {\n logger.debug(`findIssue(${title})`);\n\n /* v8 ignore next */\n if (!config.has_issues) {\n logger.debug('Issues are disabled - cannot findIssue');\n return null;\n }\n const issues = await findOpenIssues(title);\n if (!issues.length) {\n return null;\n }\n const [issue] = issues;\n return {\n number: issue.id,\n body: issue.content?.raw,\n };\n}\n\nasync function closeIssue(issueNumber: number): Promise<void> {\n await bitbucketHttp.putJson(\n `/2.0/repositories/${config.repository}/issues/${issueNumber}`,\n {\n body: { state: 'closed' },\n },\n );\n}\n\n/**\n * Remove or transform markdown into Bitbucket supported syntax.\n *\n * See https://bitbucket.org/tutorials/markdowndemo/src for supported markdown syntax\n */\n/**\n * Remove or transform markdown into Bitbucket supported syntax.\n *\n * See https://bitbucket.org/tutorials/markdowndemo/src for supported markdown syntax\n */\nexport function massageMarkdown(input: string): string {\n let massaged = smartTruncate(input, maxBodyLength())\n .replace(\n 'you tick the rebase/retry checkbox',\n 'by renaming this PR to start with \"rebase!\"',\n )\n .replace(\n 'checking the rebase/retry box above',\n 'renaming the PR to start with \"rebase!\"',\n )\n .replace(\n regEx(\n /<details>\\n(<summary>View abandoned dependencies.*<\\/summary>\\n\\n)([\\s\\S]*?)<\\/details>/,\n ),\n '$2',\n )\n .replace(regEx(`\\n---\\n\\n.*?<!-- rebase-check -->.*?\\n`), '')\n .replace(regEx(/\\]\\(\\.\\.\\/issues\\//g), '](../../issues/')\n .replace(regEx(/\\]\\(\\.\\.\\/pull\\//g), '](../../pull-requests/')\n .replace(regEx(/<!--renovate-(?:debug|config-hash):.*?-->/g), '');\n\n massaged = massageDetailSummaryHtmlToNestedLists(massaged);\n\n return massageCodeblockMarkdown(massaged);\n}\n\n/**\n * Massage codeblocks indentation to ensure correct rendering in Bitbucket.\n */\nfunction massageCodeblockMarkdown(body: string): string {\n const codeBlockRegex = regEx(\n /^(?<indent>[ \\t]*)```(?<lang>\\w*)[^\\n]*\\n(?<code>[\\s\\S]*?)\\n[ \\t]*```/gm,\n );\n let codeMatch;\n let result = body;\n\n while ((codeMatch = codeBlockRegex.exec(body)) !== null) {\n const { indent, lang, code } = codeMatch.groups!;\n const indentLength = indent.length;\n const lines = code.split('\\n');\n const cleanedLines = lines.map((line) =>\n // Remove `indentLength` characters from the start of each line\n line.slice(indentLength),\n );\n\n const cleaned = cleanedLines.join('\\n');\n const replacement = `\\`\\`\\`${lang}\\n${cleaned}\\n\\`\\`\\``;\n\n result = result.replace(codeMatch[0], replacement);\n }\n\n return result;\n}\n\n/**\n * Massage collapsible html sections into nested unordered lists.\n *\n * Bitbucket doesn't currently support collapsible syntax; https://jira.atlassian.com/browse/BCLOUD-20231\n */\nfunction massageDetailSummaryHtmlToNestedLists(body: string): string {\n let depth = 0;\n // Parse detail parts to calculate correct list depth\n const detailsParts = body.split('<details>').map((raw) => {\n const partDepth = depth;\n\n depth += 1;\n const countClosingDetailsTags = raw.split('</details>').length - 1;\n depth = Math.max(0, depth - countClosingDetailsTags);\n\n return { raw, partDepth };\n });\n\n // Reassemble parts while replacing collapsible html elements with markdown list\n return detailsParts\n .map(({ raw, partDepth }) => {\n let t = raw;\n\n if (partDepth === 0) {\n return t;\n }\n\n const partIndentation = '\\t'.repeat(partDepth - 1);\n const nestedListItemIndentation = '\\t'.repeat(partDepth);\n\n const rawContainsBlockquote = raw.includes('<blockquote>');\n\n t = t.replace(regEx(/<\\/?summary>/g), partDepth === 1 ? '**' : '`');\n\n if (partDepth > 1) {\n t = t.replace(\n regEx(/^([ \\t]*- [`[])/gm),\n `${nestedListItemIndentation}$1`,\n );\n }\n\n let result = partIndentation;\n if (rawContainsBlockquote || partDepth > 1) {\n result += ' - ';\n }\n result += t;\n\n return result;\n })\n .join('')\n .replace(/<\\/?(summary|details|blockquote)>/g, '');\n}\n\nexport function maxBodyLength(): number {\n return 250000;\n}\n\nexport async function ensureIssue({\n title,\n reuseTitle,\n body,\n}: EnsureIssueConfig): Promise<EnsureIssueResult | null> {\n logger.debug(`ensureIssue()`);\n /* v8 ignore next */\n if (!config.has_issues) {\n logger.debug('Issues are disabled - cannot ensureIssue');\n logger.debug(`Failed to ensure Issue with title:${title}`);\n return null;\n }\n try {\n let issues = await findOpenIssues(title);\n const description = massageMarkdown(sanitize(body));\n const issueKind = 'task';\n\n if (!issues.length && reuseTitle) {\n issues = await findOpenIssues(reuseTitle);\n }\n if (issues.length) {\n // Close any duplicates\n for (const issue of issues.slice(1)) {\n await closeIssue(issue.id);\n }\n const [issue] = issues;\n\n if (\n issue.title !== title ||\n String(issue.content?.raw).trim() !== description.trim() ||\n issue.kind !== issueKind\n ) {\n logger.debug('Issue updated');\n await bitbucketHttp.putJson(\n `/2.0/repositories/${config.repository}/issues/${issue.id}`,\n {\n body: {\n kind: issueKind,\n content: {\n raw: readOnlyIssueBody(description),\n markup: 'markdown',\n },\n },\n },\n );\n return 'updated';\n }\n } else {\n logger.info('Issue created');\n await bitbucketHttp.postJson(\n `/2.0/repositories/${config.repository}/issues`,\n {\n body: {\n title,\n kind: issueKind,\n content: {\n raw: readOnlyIssueBody(description),\n markup: 'markdown',\n },\n },\n },\n );\n return 'created';\n }\n } catch (err) /* v8 ignore next */ {\n if (err.message.startsWith('Repository has no issue tracker.')) {\n logger.debug(`Issues are disabled, so could not create issue: ${title}`);\n } else {\n logger.warn({ err }, 'Could not ensure issue');\n }\n }\n return null;\n}\n\n/* v8 ignore next */\nexport async function getIssueList(): Promise<Issue[]> {\n logger.debug(`getIssueList()`);\n\n if (!config.has_issues) {\n logger.debug('Issues are disabled - cannot getIssueList');\n return [];\n }\n try {\n const filters = ['(state = \"new\" OR state = \"open\")'];\n if (renovateUserUuid) {\n filters.push(`reporter.uuid=\"${renovateUserUuid}\"`);\n }\n const filter = encodeURIComponent(filters.join(' AND '));\n const url = `/2.0/repositories/${config.repository}/issues?q=${filter}`;\n const res = await bitbucketHttp.getJsonUnchecked<{ values: Issue[] }>(url, {\n cacheProvider: repoCacheProvider,\n });\n return res.body.values || [];\n } catch (err) {\n logger.warn({ err }, 'Error finding issues');\n return [];\n }\n}\n\nexport async function ensureIssueClosing(title: string): Promise<void> {\n /* v8 ignore next */\n if (!config.has_issues) {\n logger.debug('Issues are disabled - cannot ensureIssueClosing');\n return;\n }\n const issues = await findOpenIssues(title);\n for (const issue of issues) {\n await closeIssue(issue.id);\n }\n}\n\nexport function addAssignees(\n _prNr: number,\n _assignees: string[],\n): Promise<void> {\n // Bitbucket supports \"participants\" and \"reviewers\" so does not seem to have the concept of \"assignee\"\n logger.warn('Cannot add assignees');\n return Promise.resolve();\n}\n\nexport async function addReviewers(\n prId: number,\n reviewers: string[],\n): Promise<void> {\n logger.debug(`Adding reviewers '${reviewers.join(', ')}' to #${prId}`);\n\n // TODO #22198\n const { title } = (await getPr(prId))!;\n\n const body = {\n title,\n reviewers: reviewers.map((username: string) => {\n const isUUID =\n username.startsWith('{') &&\n username.endsWith('}') &&\n UUIDRegex.test(username.slice(1, -1));\n const key = isUUID ? 'uuid' : 'username';\n return {\n [key]: username,\n };\n }),\n };\n\n await bitbucketHttp.putJson(\n `/2.0/repositories/${config.repository}/pullrequests/${prId}`,\n {\n body,\n },\n );\n}\n\n/* v8 ignore next */\nexport function deleteLabel(): never {\n throw new Error('deleteLabel not implemented');\n}\n\nexport function ensureComment({\n number,\n topic,\n content,\n}: EnsureCommentConfig): Promise<boolean> {\n // https://developer.atlassian.com/bitbucket/api/2/reference/search?q=pullrequest+comment\n return comments.ensureComment({\n config,\n number,\n topic,\n content: sanitize(content),\n });\n}\n\nexport function ensureCommentRemoval(\n deleteConfig: EnsureCommentRemovalConfig,\n): Promise<void> {\n return comments.ensureCommentRemoval(config, deleteConfig);\n}\n\nasync function sanitizeReviewers(\n reviewers: Account[],\n err: any,\n): Promise<Account[] | undefined> {\n if (err.statusCode === 400 && err.body?.error?.fields?.reviewers) {\n const sanitizedReviewers: Account[] = [];\n\n const MSG_AUTHOR_AND_REVIEWER =\n 'is the author and cannot be included as a reviewer.';\n const MSG_MALFORMED_REVIEWERS_LIST = 'Malformed reviewers list';\n const MSG_NOT_WORKSPACE_MEMBER =\n 'is not a member of this workspace and cannot be added to this pull request';\n\n for (const msg of err.body.error.fields.reviewers) {\n // Bitbucket returns a 400 if any of the PR reviewer accounts are now inactive (ie: disabled/suspended)\n if (msg === MSG_MALFORMED_REVIEWERS_LIST) {\n logger.debug(\n { err },\n 'PR contains reviewers that may be either inactive or no longer a member of this workspace. Will try setting only active reviewers',\n );\n\n // Validate that each previous PR reviewer account is still active\n for (const reviewer of reviewers) {\n const reviewerUser = (\n await bitbucketHttp.getJsonUnchecked<Account>(\n `/2.0/users/${reviewer.uuid}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n )\n ).body;\n\n // There are cases where an active user may still not be a member of a workspace\n if (\n reviewerUser.account_status === 'active' &&\n (await isAccountMemberOfWorkspace(reviewer, config.repository))\n ) {\n sanitizedReviewers.push(reviewer);\n }\n }\n // Bitbucket returns a 400 if any of the PR reviewer accounts are no longer members of this workspace\n } else if (msg.endsWith(MSG_NOT_WORKSPACE_MEMBER)) {\n logger.debug(\n { err },\n 'PR contains reviewer accounts which are no longer member of this workspace. Will try setting only member reviewers',\n );\n\n // Validate that each previous PR reviewer account is still a member of this workspace\n for (const reviewer of reviewers) {\n if (await isAccountMemberOfWorkspace(reviewer, config.repository)) {\n sanitizedReviewers.push(reviewer);\n }\n }\n } else if (msg.endsWith(MSG_AUTHOR_AND_REVIEWER)) {\n logger.debug(\n { err },\n 'PR contains reviewer accounts which are also the author. Will try setting only non-author reviewers',\n );\n const author = msg.replace(MSG_AUTHOR_AND_REVIEWER, '').trim();\n for (const reviewer of reviewers) {\n if (reviewer.display_name !== author) {\n sanitizedReviewers.push(reviewer);\n }\n }\n } else {\n return undefined;\n }\n }\n\n return sanitizedReviewers;\n }\n\n return undefined;\n}\n\nasync function isAccountMemberOfWorkspace(\n reviewer: Account,\n repository: string,\n): Promise<boolean> {\n const workspace = repository.split('/')[0];\n\n try {\n await bitbucketHttp.get(\n `/2.0/workspaces/${workspace}/members/${reviewer.uuid}`,\n { cacheProvider: aggressiveRepoCacheProvider },\n );\n\n return true;\n } catch (err) {\n // HTTP 404: User cannot be found, or the user is not a member of this workspace.\n if (err.statusCode === 404) {\n logger.debug(\n { err },\n `User ${reviewer.display_name} is not a member of the workspace ${workspace}. Will be removed from the PR`,\n );\n\n return false;\n }\n throw err;\n }\n}\n\n// Creates PR and returns PR number\nexport async function createPr({\n sourceBranch,\n targetBranch,\n prTitle: title,\n prBody: description,\n draftPR = false,\n platformPrOptions,\n}: CreatePRConfig): Promise<Pr> {\n // labels is not supported in Bitbucket: https://bitbucket.org/site/master/issues/11976/ability-to-add-labels-to-pull-requests-bb\n\n const base = targetBranch;\n\n logger.debug({ repository: config.repository, title, base }, 'Creating PR');\n\n let reviewers: Account[] = [];\n\n if (platformPrOptions?.bbUseDefaultReviewers) {\n const reviewersResponse = (\n await bitbucketHttp.getJsonUnchecked<PagedResult<EffectiveReviewer>>(\n `/2.0/repositories/${config.repository}/effective-default-reviewers`,\n {\n paginate: true,\n cacheProvider: aggressiveRepoCacheProvider,\n },\n )\n ).body;\n reviewers = reviewersResponse.values.map((reviewer: EffectiveReviewer) => ({\n uuid: reviewer.user.uuid,\n display_name: reviewer.user.display_name,\n }));\n }\n\n const body = {\n title,\n description: sanitize(description),\n source: {\n branch: {\n name: sourceBranch,\n },\n },\n destination: {\n branch: {\n name: base,\n },\n },\n close_source_branch: true,\n reviewers,\n draft: draftPR,\n };\n\n try {\n const prRes = (\n await bitbucketHttp.postJson<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests`,\n {\n body,\n },\n )\n ).body;\n const pr = utils.prInfo(prRes);\n await BitbucketPrCache.setPr(\n bitbucketHttp,\n config.repository,\n renovateUserUuid,\n pr,\n );\n if (platformPrOptions?.bbAutoResolvePrTasks) {\n await autoResolvePrTasks(pr);\n }\n return pr;\n } catch (err) /* v8 ignore next */ {\n // Try sanitizing reviewers\n const sanitizedReviewers = await sanitizeReviewers(reviewers, err);\n\n if (sanitizedReviewers === undefined) {\n logger.warn({ err }, 'Error creating pull request');\n throw err;\n } else {\n const prRes = (\n await bitbucketHttp.postJson<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests`,\n {\n body: {\n ...body,\n reviewers: sanitizedReviewers,\n },\n },\n )\n ).body;\n const pr = utils.prInfo(prRes);\n await BitbucketPrCache.setPr(\n bitbucketHttp,\n config.repository,\n renovateUserUuid,\n pr,\n );\n if (platformPrOptions?.bbAutoResolvePrTasks) {\n await autoResolvePrTasks(pr);\n }\n return pr;\n }\n }\n}\n\nasync function autoResolvePrTasks(pr: Pr): Promise<void> {\n logger.debug(`Auto resolve PR tasks in #${pr.number}`);\n try {\n const unResolvedTasks = (\n await bitbucketHttp.getJson(\n `/2.0/repositories/${config.repository}/pullrequests/${pr.number}/tasks`,\n { paginate: true, pagelen: 100 },\n UnresolvedPrTasks,\n )\n ).body;\n\n logger.trace(\n {\n prId: pr.number,\n listTaskRes: unResolvedTasks,\n },\n 'List PR tasks',\n );\n\n for (const task of unResolvedTasks) {\n const res = await bitbucketHttp.putJson(\n `/2.0/repositories/${config.repository}/pullrequests/${pr.number}/tasks/${task.id}`,\n {\n body: {\n state: 'RESOLVED',\n content: {\n raw: task.content.raw,\n },\n },\n },\n );\n logger.trace(\n {\n prId: pr.number,\n updateTaskResponse: res,\n },\n 'Put PR tasks - mark resolved',\n );\n }\n } catch (err) {\n logger.warn({ prId: pr.number, err }, 'Error resolving PR tasks');\n }\n}\n\nexport async function updatePr({\n number: prNo,\n prTitle: title,\n prBody: description,\n state,\n targetBranch,\n}: UpdatePrConfig): Promise<void> {\n logger.debug(`updatePr(${prNo}, ${title}, body)`);\n // Updating a PR in Bitbucket will clear the reviewers if reviewers is not present\n const pr = (\n await bitbucketHttp.getJsonUnchecked<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,\n )\n ).body;\n\n let updatedPrRes: PrResponse;\n try {\n const body: any = {\n title,\n description: sanitize(description),\n reviewers: pr.reviewers,\n };\n if (targetBranch) {\n body.destination = {\n branch: {\n name: targetBranch,\n },\n };\n }\n\n updatedPrRes = (\n await bitbucketHttp.putJson<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,\n { body },\n )\n ).body;\n } catch (err) {\n // Try sanitizing reviewers\n const sanitizedReviewers = await sanitizeReviewers(pr.reviewers, err);\n\n if (sanitizedReviewers === undefined) {\n throw err;\n } else {\n updatedPrRes = (\n await bitbucketHttp.putJson<PrResponse>(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}`,\n {\n body: {\n title,\n description: sanitize(description),\n reviewers: sanitizedReviewers,\n },\n },\n )\n ).body;\n }\n }\n\n if (state === 'closed' && pr) {\n await bitbucketHttp.postJson(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}/decline`,\n );\n }\n\n // update pr cache\n await BitbucketPrCache.setPr(\n bitbucketHttp,\n config.repository,\n renovateUserUuid,\n utils.prInfo({ ...updatedPrRes, ...(state && { state }) }),\n );\n}\n\nexport async function mergePr({\n branchName,\n id: prNo,\n strategy: mergeStrategy,\n}: MergePRConfig): Promise<boolean> {\n logger.debug(`mergePr(${prNo}, ${branchName}, ${mergeStrategy})`);\n\n // Bitbucket Cloud does not support a rebase-alike; https://jira.atlassian.com/browse/BCLOUD-16610\n if (mergeStrategy === 'rebase') {\n logger.warn('Bitbucket Cloud does not support a \"rebase\" strategy.');\n return false;\n }\n\n try {\n await bitbucketHttp.postJson(\n `/2.0/repositories/${config.repository}/pullrequests/${prNo}/merge`,\n {\n body: mergeBodyTransformer(mergeStrategy),\n },\n );\n logger.debug('Automerging succeeded');\n } catch (err) /* v8 ignore next */ {\n logger.debug({ err }, `PR merge error`);\n logger.info({ pr: prNo }, 'PR automerge failed');\n return false;\n }\n return true;\n}\n"],"mappings":"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"}
|
|
@@ -181,8 +181,8 @@ async function getRepos() {
|
|
|
181
181
|
let reposRes;
|
|
182
182
|
try {
|
|
183
183
|
reposRes = await listRepositories();
|
|
184
|
-
} catch (
|
|
185
|
-
logger.error({
|
|
184
|
+
} catch (err) {
|
|
185
|
+
logger.error({ err }, "Could not retrieve repositories");
|
|
186
186
|
return [];
|
|
187
187
|
}
|
|
188
188
|
const res = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["client.listRepositories","client.getRepositoryInfo","client.getCodeCommitUrl","git.initRepo","client.listPullRequests","client.getPr","client.getFile","client.createPr","client.updatePrDescription","client.updatePrTitle","client.updatePrStatus","client.createPrApprovalRule","client.getPrComments","client.createPrComment","client.updateComment","client.deleteComment"],"sources":["../../../../lib/modules/platform/codecommit/index.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport type {\n GetCommentsForPullRequestOutput,\n ListRepositoriesOutput,\n} from '@aws-sdk/client-codecommit';\nimport { PullRequestStatusEnum } from '@aws-sdk/client-codecommit';\nimport {\n PLATFORM_BAD_CREDENTIALS,\n REPOSITORY_EMPTY,\n REPOSITORY_NOT_FOUND,\n} from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport type { BranchStatus, PrState } from '../../../types/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { parseJson } from '../../../util/common.ts';\nimport * as git from '../../../util/git/index.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { sanitize } from '../../../util/sanitize.ts';\nimport type {\n BranchStatusConfig,\n CreatePRConfig,\n EnsureCommentConfig,\n EnsureCommentRemovalConfig,\n EnsureIssueConfig,\n EnsureIssueResult,\n FindPRConfig,\n Issue,\n MergePRConfig,\n PlatformParams,\n PlatformResult,\n Pr,\n RepoParams,\n RepoResult,\n UpdatePrConfig,\n} from '../types.ts';\nimport { getNewBranchName, repoFingerprint } from '../util.ts';\nimport { smartTruncate } from '../utils/pr-body.ts';\nimport * as client from './codecommit-client.ts';\n\nexport interface CodeCommitPr extends Pr {\n body: string;\n destinationCommit: string;\n sourceCommit: string;\n}\n\ninterface Config {\n repository?: string;\n defaultBranch?: string;\n region?: string;\n prList?: CodeCommitPr[];\n}\n\nexport const id = 'codecommit';\nexport const experimental = true;\n\nconst platformConfig = {\n endpoint: 'https://git-codecommit.us-east-1.amazonaws.com',\n};\n\nlet config: Config = {} as any;\n\nexport async function initPlatform({\n endpoint,\n username,\n password,\n token: awsToken,\n}: PlatformParams): Promise<PlatformResult> {\n const accessKeyId = username;\n const secretAccessKey = password;\n const env = process.env;\n let region: string | undefined;\n\n if (accessKeyId) {\n env.AWS_ACCESS_KEY_ID = accessKeyId;\n }\n if (secretAccessKey) {\n env.AWS_SECRET_ACCESS_KEY = secretAccessKey;\n }\n if (awsToken) {\n env.AWS_SESSION_TOKEN = awsToken;\n }\n\n if (endpoint) {\n const regionReg = regEx(/.*codecommit\\.(?<region>.+)\\.amazonaws\\.com/);\n const codeCommitMatch = regionReg.exec(endpoint);\n region = codeCommitMatch?.groups?.region;\n if (region) {\n env.AWS_REGION = region;\n } else {\n logger.warn(\"Can't parse region, make sure your endpoint is correct\");\n }\n }\n\n // If any of the below fails, it will throw an exception stopping the program.\n client.buildCodeCommitClient();\n // To check if we have permission to codecommit, throws exception if failed.\n await client.listRepositories();\n\n platformConfig.endpoint =\n endpoint ??\n `https://git-codecommit.${env.AWS_REGION ?? 'us-east-1'}.amazonaws.com/`;\n\n const platformResult: PlatformResult = {\n endpoint: platformConfig.endpoint,\n };\n return platformResult;\n}\n\nexport async function initRepo({\n repository,\n}: RepoParams): Promise<RepoResult> {\n logger.debug(`initRepo(\"${repository}\")`);\n\n config = { repository } as Config;\n\n let repo;\n try {\n repo = await client.getRepositoryInfo(repository);\n } catch (err) {\n logger.error({ err }, 'Could not find repository');\n throw new Error(REPOSITORY_NOT_FOUND);\n }\n\n if (!repo?.repositoryMetadata) {\n logger.error({ repository }, 'Could not find repository');\n throw new Error(REPOSITORY_NOT_FOUND);\n }\n logger.debug({ repositoryDetails: repo }, 'Repository details');\n const metadata = repo.repositoryMetadata;\n\n const url = client.getCodeCommitUrl(metadata, repository);\n try {\n await git.initRepo({\n url,\n });\n } catch (err) {\n logger.debug({ err }, 'Failed to git init');\n throw new Error(PLATFORM_BAD_CREDENTIALS);\n }\n\n if (!metadata.defaultBranch || !metadata.repositoryId) {\n logger.debug('Repo is empty');\n throw new Error(REPOSITORY_EMPTY);\n }\n\n const defaultBranch = metadata.defaultBranch;\n config.defaultBranch = defaultBranch;\n logger.debug(`${repository} default branch = ${defaultBranch}`);\n\n return {\n repoFingerprint: repoFingerprint(\n metadata.repositoryId,\n platformConfig.endpoint,\n ),\n defaultBranch,\n isFork: false,\n };\n}\n\nexport async function getPrList(): Promise<CodeCommitPr[]> {\n logger.debug('getPrList()');\n\n if (config.prList) {\n return config.prList;\n }\n\n const listPrsResponse = await client.listPullRequests(config.repository!);\n const fetchedPrs: CodeCommitPr[] = [];\n\n if (listPrsResponse && !listPrsResponse.pullRequestIds) {\n return fetchedPrs;\n }\n\n const prIds = coerceArray(listPrsResponse.pullRequestIds);\n\n for (const prId of prIds) {\n const prRes = await client.getPr(prId);\n\n if (!prRes?.pullRequest) {\n continue;\n }\n const prInfo = prRes.pullRequest;\n const pr: CodeCommitPr = {\n targetBranch: prInfo.pullRequestTargets![0].destinationReference!,\n sourceBranch: prInfo.pullRequestTargets![0].sourceReference!,\n destinationCommit: prInfo.pullRequestTargets![0].destinationCommit!,\n sourceCommit: prInfo.pullRequestTargets![0].sourceCommit!,\n state:\n prInfo.pullRequestStatus === PullRequestStatusEnum.OPEN\n ? 'open'\n : 'closed',\n number: Number.parseInt(prId, 10),\n title: prInfo.title!,\n body: prInfo.description!,\n createdAt: prInfo.creationDate?.toISOString(),\n };\n fetchedPrs.push(pr);\n }\n\n config.prList = fetchedPrs;\n\n logger.debug(`Retrieved Pull Requests, count: ${fetchedPrs.length}`);\n return fetchedPrs;\n}\n\nexport async function findPr({\n branchName,\n prTitle,\n state = 'all',\n}: FindPRConfig): Promise<CodeCommitPr | null> {\n let prsFiltered: CodeCommitPr[] = [];\n try {\n const prs = await getPrList();\n const refsHeadBranchName = getNewBranchName(branchName);\n prsFiltered = prs.filter(\n (item) => item.sourceBranch === refsHeadBranchName,\n );\n\n if (prTitle) {\n prsFiltered = prsFiltered.filter(\n (item) => item.title.toUpperCase() === prTitle.toUpperCase(),\n );\n }\n\n switch (state) {\n case 'all':\n break;\n case '!open':\n prsFiltered = prsFiltered.filter((item) => item.state !== 'open');\n break;\n default:\n prsFiltered = prsFiltered.filter((item) => item.state === 'open');\n break;\n }\n } catch (err) {\n logger.error({ err }, 'findPr error');\n }\n if (prsFiltered.length === 0) {\n return null;\n }\n return prsFiltered[0];\n}\n\nexport async function getBranchPr(\n branchName: string,\n): Promise<CodeCommitPr | null> {\n logger.debug(`getBranchPr(${branchName})`);\n const existingPr = await findPr({\n branchName,\n state: 'open',\n });\n return existingPr ? getPr(existingPr.number) : null;\n}\n\nexport async function getPr(\n pullRequestId: number,\n): Promise<CodeCommitPr | null> {\n logger.debug(`getPr(${pullRequestId})`);\n const prRes = await client.getPr(`${pullRequestId}`);\n\n if (!prRes?.pullRequest) {\n return null;\n }\n\n const prInfo = prRes.pullRequest;\n let prState: PrState;\n if (prInfo.pullRequestTargets![0].mergeMetadata?.isMerged) {\n prState = 'merged';\n } else {\n prState =\n prInfo.pullRequestStatus === PullRequestStatusEnum.OPEN\n ? 'open'\n : 'closed';\n }\n\n return {\n sourceBranch: prInfo.pullRequestTargets![0].sourceReference!,\n sourceCommit: prInfo.pullRequestTargets![0].sourceCommit!,\n state: prState,\n number: pullRequestId,\n title: prInfo.title!,\n targetBranch: prInfo.pullRequestTargets![0].destinationReference!,\n destinationCommit: prInfo.pullRequestTargets![0].destinationCommit!,\n body: prInfo.description!,\n };\n}\n\nexport async function getRepos(): Promise<string[]> {\n logger.debug('Autodiscovering AWS CodeCommit repositories');\n\n let reposRes: ListRepositoriesOutput;\n try {\n reposRes = await client.listRepositories();\n //todo do we need pagination? maximum number of repos is 1000 without pagination, also the same for free account\n } catch (error) {\n logger.error({ error }, 'Could not retrieve repositories');\n return [];\n }\n\n const res: string[] = [];\n\n const repoNames = coerceArray(reposRes?.repositories);\n\n for (const repo of repoNames) {\n // v8 ignore else -- TODO: add test #40625\n if (repo.repositoryName) {\n res.push(repo.repositoryName);\n }\n }\n\n return res;\n}\n\nexport function massageMarkdown(input: string): string {\n // Remove any HTML we use\n return input\n .replace(\n 'you tick the rebase/retry checkbox',\n 'PR is renamed to start with \"rebase!\"',\n )\n .replace(\n 'checking the rebase/retry box above',\n 'renaming the PR to start with \"rebase!\"',\n )\n .replace(regEx(/<\\/?summary>/g), '**')\n .replace(regEx(/<\\/?details>/g), '')\n .replace(regEx(`\\n---\\n\\n.*?<!-- rebase-check -->.*?\\n`), '')\n .replace(regEx(/\\]\\(\\.\\.\\/issues\\//g), '](#')\n .replace(regEx(/\\]\\(\\.\\.\\/pull\\//g), '](../../pull-requests/')\n .replace(\n regEx(/(?<hiddenComment><!--renovate-(?:debug|config-hash):.*?-->)/g),\n '[//]: # ($<hiddenComment>)',\n );\n}\n\n/**\n * Unsed, no Dashboard\n */\nexport function maxBodyLength(): number {\n return Infinity;\n}\n\nexport async function getJsonFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n): Promise<any> {\n const raw = await getRawFile(fileName, repoName, branchOrTag);\n return parseJson(raw, fileName);\n}\n\nexport async function getRawFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n): Promise<string | null> {\n const fileRes = await client.getFile(\n repoName ?? config.repository,\n fileName,\n branchOrTag,\n );\n if (!fileRes?.fileContent) {\n return null;\n }\n const buf = Buffer.from(fileRes.fileContent);\n return buf.toString();\n}\n\nconst AMAZON_MAX_BODY_LENGTH = 10239;\n\nexport async function createPr({\n sourceBranch,\n targetBranch,\n prTitle: title,\n prBody: body,\n}: CreatePRConfig): Promise<CodeCommitPr> {\n const description = smartTruncate(sanitize(body), AMAZON_MAX_BODY_LENGTH);\n\n const prCreateRes = await client.createPr(\n title,\n sanitize(description),\n sourceBranch,\n targetBranch,\n config.repository,\n );\n\n if (\n !prCreateRes.pullRequest?.title ||\n !prCreateRes.pullRequest?.pullRequestId ||\n !prCreateRes.pullRequest?.description ||\n !prCreateRes.pullRequest?.pullRequestTargets?.length\n ) {\n throw new Error('Could not create pr, missing PR info');\n }\n\n return {\n number: Number.parseInt(prCreateRes.pullRequest.pullRequestId, 10),\n state: 'open',\n title: prCreateRes.pullRequest.title,\n sourceBranch,\n targetBranch,\n sourceCommit: prCreateRes.pullRequest.pullRequestTargets[0].sourceCommit!,\n destinationCommit:\n prCreateRes.pullRequest.pullRequestTargets[0].destinationCommit!,\n sourceRepo: config.repository,\n body: prCreateRes.pullRequest.description,\n };\n}\n\nexport async function updatePr({\n number: prNo,\n prTitle: title,\n prBody: body,\n state,\n}: UpdatePrConfig): Promise<void> {\n logger.debug(`updatePr(${prNo}, ${title}, body)`);\n\n let cachedPr: CodeCommitPr | undefined = undefined;\n const cachedPrs = config.prList ?? [];\n for (const p of cachedPrs) {\n // v8 ignore else -- TODO: add test #40625\n if (p.number === prNo) {\n cachedPr = p;\n }\n }\n\n // v8 ignore else -- TODO: add test #40625\n if (body && cachedPr?.body !== body) {\n await client.updatePrDescription(\n `${prNo}`,\n smartTruncate(sanitize(body), AMAZON_MAX_BODY_LENGTH),\n );\n }\n\n // v8 ignore else -- TODO: add test #40625\n if (title && cachedPr?.title !== title) {\n await client.updatePrTitle(`${prNo}`, title);\n }\n\n const prStatusInput =\n state === 'closed'\n ? PullRequestStatusEnum.CLOSED\n : PullRequestStatusEnum.OPEN;\n // v8 ignore else -- TODO: add test #40625\n if (cachedPr?.state !== prStatusInput) {\n try {\n await client.updatePrStatus(`${prNo}`, prStatusInput);\n } catch {\n // safety check\n // do nothing, it's ok to fail sometimes when trying to update from open to open or from closed to closed.\n }\n }\n}\n\n// Auto-Merge not supported currently.\n/* v8 ignore next */\nexport async function mergePr({\n branchName,\n id: prNo,\n}: MergePRConfig): Promise<boolean> {\n logger.debug(`mergePr(${prNo}, ${branchName!})`);\n await client.getPr(`${prNo}`);\n return Promise.resolve(false);\n //\n // /* v8 ignore next */\n // if (!prOut) {\n // return false;\n // }\n // const pReq = prOut.pullRequest;\n // const targets = pReq?.pullRequestTargets;\n //\n // /* v8 ignore next */\n // if (!targets) {\n // return false;\n // }\n //\n // if (strategy === 'rebase') {\n // logger.warn('CodeCommit does not support a \"rebase\" strategy.');\n // return false;\n // }\n //\n // try {\n // if (strategy === 'auto' || strategy === 'squash') {\n // await client.squashMerge(\n // targets[0].repositoryName!,\n // targets[0].sourceReference!,\n // targets[0].destinationReference!,\n // pReq?.title\n // );\n // } else if (strategy === 'fast-forward') {\n // await client.fastForwardMerge(\n // targets[0].repositoryName!,\n // targets[0].sourceReference!,\n // targets[0].destinationReference!\n // );\n // } else {\n // logger.debug(`unsupported strategy`);\n // return false;\n // }\n // } catch (err) {\n // logger.debug({ err }, `PR merge error`);\n // logger.info({ pr: prNo }, 'PR automerge failed');\n // return false;\n // }\n //\n // logger.trace(`Updating PR ${prNo} to status ${PullRequestStatusEnum.CLOSED}`);\n //\n // try {\n // const response = await client.updatePrStatus(\n // `${prNo}`,\n // PullRequestStatusEnum.CLOSED\n // );\n // const isClosed =\n // response.pullRequest?.pullRequestStatus === PullRequestStatusEnum.CLOSED;\n //\n // if (!isClosed) {\n // logger.warn(\n // {\n // pullRequestId: prNo,\n // status: response.pullRequest?.pullRequestStatus,\n // },\n // `Expected PR to have status`\n // );\n // }\n // return true;\n // } catch (err) {\n // logger.debug({ err }, 'Failed to set the PR as Closed.');\n // return false;\n // }\n}\n\nexport async function addReviewers(\n prNo: number,\n reviewers: string[],\n): Promise<void> {\n const numberOfApprovers = reviewers.length;\n const approvalRuleContents = `{\"Version\":\"2018-11-08\",\"Statements\": [{\"Type\": \"Approvers\",\"NumberOfApprovalsNeeded\":${numberOfApprovers},\"ApprovalPoolMembers\": ${JSON.stringify(\n reviewers,\n )}}]}`;\n const res = await client.createPrApprovalRule(\n `${prNo}`,\n approvalRuleContents,\n );\n // v8 ignore else -- TODO: add test #40625\n if (res) {\n const approvalRule = res.approvalRule;\n logger.debug({ approvalRule }, `Approval Rule Added to PR #${prNo}:`);\n }\n}\n\n/* v8 ignore next */\nexport function addAssignees(\n _iid: number,\n _assignees: string[],\n): Promise<void> {\n // CodeCommit does not support adding reviewers\n return Promise.resolve();\n}\n\n/* v8 ignore next */\nexport function findIssue(_title: string): Promise<Issue | null> {\n // CodeCommit does not have issues\n return Promise.resolve(null);\n}\n\n/* v8 ignore next */\nexport function ensureIssue(\n _cfg: EnsureIssueConfig,\n): Promise<EnsureIssueResult | null> {\n // CodeCommit does not have issues\n return Promise.resolve(null);\n}\n\n/* v8 ignore next */\nexport function getIssueList(): Promise<Issue[]> {\n // CodeCommit does not have issues\n return Promise.resolve([]);\n}\n\n/* v8 ignore next */\nexport function ensureIssueClosing(_title: string): Promise<void> {\n // CodeCommit does not have issues\n return Promise.resolve();\n}\n\n/* v8 ignore next */\nexport function deleteLabel(_prNumber: number, _label: string): Promise<void> {\n return Promise.resolve();\n}\n\n// Returns the combined status for a branch.\n/* v8 ignore next */\nexport function getBranchStatus(branchName: string): Promise<BranchStatus> {\n logger.debug(`getBranchStatus(${branchName})`);\n logger.debug(\n 'returning branch status yellow, because getBranchStatus isnt supported on aws yet',\n );\n return Promise.resolve('yellow');\n}\n\n/* v8 ignore next */\nexport function getBranchStatusCheck(\n branchName: string,\n context: string,\n): Promise<BranchStatus | null> {\n logger.debug(`getBranchStatusCheck(${branchName}, context=${context})`);\n logger.debug(\n 'returning null, because getBranchStatusCheck is not supported on aws yet',\n );\n return Promise.resolve(null);\n}\n\n/* v8 ignore next */\nexport function setBranchStatus(_cfg: BranchStatusConfig): Promise<void> {\n return Promise.resolve();\n}\n\nexport async function ensureComment({\n number,\n topic,\n content,\n}: EnsureCommentConfig): Promise<boolean> {\n logger.debug(`ensureComment(${number}, ${topic!}, content)`);\n const header = topic ? `### ${topic}\\n\\n` : '';\n const body = `${header}${sanitize(content)}`;\n let prCommentsResponse: GetCommentsForPullRequestOutput;\n try {\n prCommentsResponse = await client.getPrComments(`${number}`);\n } catch (err) {\n logger.debug({ err }, 'Unable to retrieve pr comments');\n return false;\n }\n\n let commentId: string | undefined = undefined;\n let commentNeedsUpdating = false;\n\n if (!prCommentsResponse?.commentsForPullRequestData) {\n return false;\n }\n\n for (const commentObj of prCommentsResponse.commentsForPullRequestData) {\n if (!commentObj?.comments) {\n continue;\n }\n const firstCommentContent = commentObj.comments[0].content;\n if (\n (topic && firstCommentContent?.startsWith(header)) === true ||\n (!topic && firstCommentContent === body)\n ) {\n commentId = commentObj.comments[0].commentId;\n commentNeedsUpdating = firstCommentContent !== body;\n break;\n }\n }\n\n if (!commentId) {\n const prs = await getPrList();\n const thisPr = prs.filter((item) => item.number === number);\n\n if (!thisPr[0].sourceCommit || !thisPr[0].destinationCommit) {\n return false;\n }\n\n await client.createPrComment(\n `${number}`,\n config.repository,\n body,\n thisPr[0].destinationCommit,\n thisPr[0].sourceCommit,\n );\n logger.info(\n { repository: config.repository, prNo: number, topic },\n 'Comment added',\n );\n } else if (commentNeedsUpdating && commentId) {\n await client.updateComment(commentId, body);\n\n logger.debug(\n { repository: config.repository, prNo: number, topic },\n 'Comment updated',\n );\n } else {\n logger.debug(\n { repository: config.repository, prNo: number, topic },\n 'Comment is already up-to-date',\n );\n }\n\n return true;\n}\n\nexport async function ensureCommentRemoval(\n removeConfig: EnsureCommentRemovalConfig,\n): Promise<void> {\n const { number: prNo } = removeConfig;\n const key =\n removeConfig.type === 'by-topic'\n ? removeConfig.topic\n : removeConfig.content;\n logger.debug(`Ensuring comment \"${key}\" in #${prNo} is removed`);\n\n let prCommentsResponse: GetCommentsForPullRequestOutput;\n try {\n prCommentsResponse = await client.getPrComments(`${prNo}`);\n } catch (err) {\n logger.debug({ err }, 'Unable to retrieve pr comments');\n return;\n }\n\n if (!prCommentsResponse?.commentsForPullRequestData) {\n logger.debug('commentsForPullRequestData not found');\n return;\n }\n\n let commentIdToRemove: string | undefined;\n for (const commentObj of prCommentsResponse.commentsForPullRequestData) {\n if (!commentObj?.comments) {\n logger.debug(\n 'comments object not found under commentsForPullRequestData',\n );\n continue;\n }\n\n for (const comment of commentObj.comments) {\n // v8 ignore else -- TODO: add test #40625\n if (\n (removeConfig.type === 'by-topic' &&\n comment.content?.startsWith(`### ${removeConfig.topic}\\n\\n`)) ===\n true ||\n (removeConfig.type === 'by-content' &&\n removeConfig.content === comment.content?.trim())\n ) {\n commentIdToRemove = comment.commentId;\n break;\n }\n }\n // v8 ignore else -- TODO: add test #40625\n if (commentIdToRemove) {\n await client.deleteComment(commentIdToRemove);\n logger.debug(`comment \"${key}\" in PR #${prNo} was removed`);\n break;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAa,KAAK;AAGlB,MAAM,iBAAiB,EACrB,UAAU,iDACZ;AAEA,IAAI,SAAiB,CAAC;AAEtB,eAAsB,aAAa,EACjC,UACA,UACA,UACA,OAAO,YACmC;CAC1C,MAAM,cAAc;CACpB,MAAM,kBAAkB;CACxB,MAAM,MAAM,QAAQ;CACpB,IAAI;CAEJ,IAAI,aACF,IAAI,oBAAoB;CAE1B,IAAI,iBACF,IAAI,wBAAwB;CAE9B,IAAI,UACF,IAAI,oBAAoB;CAG1B,IAAI,UAAU;EAGZ,SAFkB,MAAM,6CACQ,CAAC,CAAC,KAAK,QAChB,CAAC,EAAE,QAAQ;EAClC,IAAI,QACF,IAAI,aAAa;OAEjB,OAAO,KAAK,wDAAwD;CAExE;CAGA,sBAA6B;CAE7B,MAAMA,iBAAwB;CAE9B,eAAe,WACb,YACA,0BAA0B,IAAI,cAAc,YAAY;CAK1D,OAAO,EAFL,UAAU,eAAe,SAEP;AACtB;AAEA,eAAsB,SAAS,EAC7B,cACkC;CAClC,OAAO,MAAM,aAAa,WAAW,GAAG;CAExC,SAAS,EAAE,WAAW;CAEtB,IAAI;CACJ,IAAI;EACF,OAAO,MAAMC,kBAAyB,UAAU;CAClD,SAAS,KAAK;EACZ,OAAO,MAAM,EAAE,IAAI,GAAG,2BAA2B;EACjD,MAAM,IAAI,MAAM,oBAAoB;CACtC;CAEA,IAAI,CAAC,MAAM,oBAAoB;EAC7B,OAAO,MAAM,EAAE,WAAW,GAAG,2BAA2B;EACxD,MAAM,IAAI,MAAM,oBAAoB;CACtC;CACA,OAAO,MAAM,EAAE,mBAAmB,KAAK,GAAG,oBAAoB;CAC9D,MAAM,WAAW,KAAK;CAEtB,MAAM,MAAMC,iBAAwB,UAAU,UAAU;CACxD,IAAI;EACF,MAAMC,WAAa,EACjB,IACF,CAAC;CACH,SAAS,KAAK;EACZ,OAAO,MAAM,EAAE,IAAI,GAAG,oBAAoB;EAC1C,MAAM,IAAI,MAAM,wBAAwB;CAC1C;CAEA,IAAI,CAAC,SAAS,iBAAiB,CAAC,SAAS,cAAc;EACrD,OAAO,MAAM,eAAe;EAC5B,MAAM,IAAI,MAAM,gBAAgB;CAClC;CAEA,MAAM,gBAAgB,SAAS;CAC/B,OAAO,gBAAgB;CACvB,OAAO,MAAM,GAAG,WAAW,oBAAoB,eAAe;CAE9D,OAAO;EACL,iBAAiB,gBACf,SAAS,cACT,eAAe,QACjB;EACA;EACA,QAAQ;CACV;AACF;AAEA,eAAsB,YAAqC;CACzD,OAAO,MAAM,aAAa;CAE1B,IAAI,OAAO,QACT,OAAO,OAAO;CAGhB,MAAM,kBAAkB,MAAMC,iBAAwB,OAAO,UAAW;CACxE,MAAM,aAA6B,CAAC;CAEpC,IAAI,mBAAmB,CAAC,gBAAgB,gBACtC,OAAO;CAGT,MAAM,QAAQ,YAAY,gBAAgB,cAAc;CAExD,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,MAAMC,QAAa,IAAI;EAErC,IAAI,CAAC,OAAO,aACV;EAEF,MAAM,SAAS,MAAM;EACrB,MAAM,KAAmB;GACvB,cAAc,OAAO,mBAAoB,EAAE,CAAC;GAC5C,cAAc,OAAO,mBAAoB,EAAE,CAAC;GAC5C,mBAAmB,OAAO,mBAAoB,EAAE,CAAC;GACjD,cAAc,OAAO,mBAAoB,EAAE,CAAC;GAC5C,OACE,OAAO,sBAAsB,sBAAsB,OAC/C,SACA;GACN,QAAQ,OAAO,SAAS,MAAM,EAAE;GAChC,OAAO,OAAO;GACd,MAAM,OAAO;GACb,WAAW,OAAO,cAAc,YAAY;EAC9C;EACA,WAAW,KAAK,EAAE;CACpB;CAEA,OAAO,SAAS;CAEhB,OAAO,MAAM,mCAAmC,WAAW,QAAQ;CACnE,OAAO;AACT;AAEA,eAAsB,OAAO,EAC3B,YACA,SACA,QAAQ,SACqC;CAC7C,IAAI,cAA8B,CAAC;CACnC,IAAI;EACF,MAAM,MAAM,MAAM,UAAU;EAC5B,MAAM,qBAAqB,iBAAiB,UAAU;EACtD,cAAc,IAAI,QACf,SAAS,KAAK,iBAAiB,kBAClC;EAEA,IAAI,SACF,cAAc,YAAY,QACvB,SAAS,KAAK,MAAM,YAAY,MAAM,QAAQ,YAAY,CAC7D;EAGF,QAAQ,OAAR;GACE,KAAK,OACH;GACF,KAAK;IACH,cAAc,YAAY,QAAQ,SAAS,KAAK,UAAU,MAAM;IAChE;GACF;IACE,cAAc,YAAY,QAAQ,SAAS,KAAK,UAAU,MAAM;IAChE;EACJ;CACF,SAAS,KAAK;EACZ,OAAO,MAAM,EAAE,IAAI,GAAG,cAAc;CACtC;CACA,IAAI,YAAY,WAAW,GACzB,OAAO;CAET,OAAO,YAAY;AACrB;AAEA,eAAsB,YACpB,YAC8B;CAC9B,OAAO,MAAM,eAAe,WAAW,EAAE;CACzC,MAAM,aAAa,MAAM,OAAO;EAC9B;EACA,OAAO;CACT,CAAC;CACD,OAAO,aAAa,MAAM,WAAW,MAAM,IAAI;AACjD;AAEA,eAAsB,MACpB,eAC8B;CAC9B,OAAO,MAAM,SAAS,cAAc,EAAE;CACtC,MAAM,QAAQ,MAAMA,QAAa,GAAG,eAAe;CAEnD,IAAI,CAAC,OAAO,aACV,OAAO;CAGT,MAAM,SAAS,MAAM;CACrB,IAAI;CACJ,IAAI,OAAO,mBAAoB,EAAE,CAAC,eAAe,UAC/C,UAAU;MAEV,UACE,OAAO,sBAAsB,sBAAsB,OAC/C,SACA;CAGR,OAAO;EACL,cAAc,OAAO,mBAAoB,EAAE,CAAC;EAC5C,cAAc,OAAO,mBAAoB,EAAE,CAAC;EAC5C,OAAO;EACP,QAAQ;EACR,OAAO,OAAO;EACd,cAAc,OAAO,mBAAoB,EAAE,CAAC;EAC5C,mBAAmB,OAAO,mBAAoB,EAAE,CAAC;EACjD,MAAM,OAAO;CACf;AACF;AAEA,eAAsB,WAA8B;CAClD,OAAO,MAAM,6CAA6C;CAE1D,IAAI;CACJ,IAAI;EACF,WAAW,MAAML,iBAAwB;CAE3C,SAAS,OAAO;EACd,OAAO,MAAM,EAAE,MAAM,GAAG,iCAAiC;EACzD,OAAO,CAAC;CACV;CAEA,MAAM,MAAgB,CAAC;CAEvB,MAAM,YAAY,YAAY,UAAU,YAAY;CAEpD,KAAK,MAAM,QAAQ;;CAEjB,IAAI,KAAK,gBACP,IAAI,KAAK,KAAK,cAAc;CAIhC,OAAO;AACT;AAEA,SAAgB,gBAAgB,OAAuB;CAErD,OAAO,MACJ,QACC,sCACA,yCACF,CAAC,CACA,QACC,uCACA,2CACF,CAAC,CACA,QAAQ,MAAM,eAAe,GAAG,IAAI,CAAC,CACrC,QAAQ,MAAM,eAAe,GAAG,EAAE,CAAC,CACnC,QAAQ,MAAM,wCAAwC,GAAG,EAAE,CAAC,CAC5D,QAAQ,MAAM,qBAAqB,GAAG,KAAK,CAAC,CAC5C,QAAQ,MAAM,mBAAmB,GAAG,wBAAwB,CAAC,CAC7D,QACC,MAAM,8DAA8D,GACpE,4BACF;AACJ;;;;AAKA,SAAgB,gBAAwB;CACtC,OAAO;AACT;AAEA,eAAsB,YACpB,UACA,UACA,aACc;CAEd,OAAO,UAAU,MADC,WAAW,UAAU,UAAU,WAAW,GACtC,QAAQ;AAChC;AAEA,eAAsB,WACpB,UACA,UACA,aACwB;CACxB,MAAM,UAAU,MAAMM,QACpB,YAAY,OAAO,YACnB,UACA,WACF;CACA,IAAI,CAAC,SAAS,aACZ,OAAO;CAGT,OADY,OAAO,KAAK,QAAQ,WACvB,CAAC,CAAC,SAAS;AACtB;AAEA,MAAM,yBAAyB;AAE/B,eAAsB,SAAS,EAC7B,cACA,cACA,SAAS,OACT,QAAQ,QACgC;CAGxC,MAAM,cAAc,MAAMC,WACxB,OACA,SAJkB,cAAc,SAAS,IAAI,GAAG,sBAIvC,CAAW,GACpB,cACA,cACA,OAAO,UACT;CAEA,IACE,CAAC,YAAY,aAAa,SAC1B,CAAC,YAAY,aAAa,iBAC1B,CAAC,YAAY,aAAa,eAC1B,CAAC,YAAY,aAAa,oBAAoB,QAE9C,MAAM,IAAI,MAAM,sCAAsC;CAGxD,OAAO;EACL,QAAQ,OAAO,SAAS,YAAY,YAAY,eAAe,EAAE;EACjE,OAAO;EACP,OAAO,YAAY,YAAY;EAC/B;EACA;EACA,cAAc,YAAY,YAAY,mBAAmB,EAAE,CAAC;EAC5D,mBACE,YAAY,YAAY,mBAAmB,EAAE,CAAC;EAChD,YAAY,OAAO;EACnB,MAAM,YAAY,YAAY;CAChC;AACF;AAEA,eAAsB,SAAS,EAC7B,QAAQ,MACR,SAAS,OACT,QAAQ,MACR,SACgC;CAChC,OAAO,MAAM,YAAY,KAAK,IAAI,MAAM,QAAQ;CAEhD,IAAI,WAAqC,KAAA;CACzC,MAAM,YAAY,OAAO,UAAU,CAAC;CACpC,KAAK,MAAM,KAAK;;CAEd,IAAI,EAAE,WAAW,MACf,WAAW;;CAKf,IAAI,QAAQ,UAAU,SAAS,MAC7B,MAAMC,oBACJ,GAAG,QACH,cAAc,SAAS,IAAI,GAAG,sBAAsB,CACtD;;CAIF,IAAI,SAAS,UAAU,UAAU,OAC/B,MAAMC,cAAqB,GAAG,QAAQ,KAAK;CAG7C,MAAM,gBACJ,UAAU,WACN,sBAAsB,SACtB,sBAAsB;;CAE5B,IAAI,UAAU,UAAU,eACtB,IAAI;EACF,MAAMC,eAAsB,GAAG,QAAQ,aAAa;CACtD,QAAQ,CAGR;AAEJ;;AAIA,eAAsB,QAAQ,EAC5B,YACA,IAAI,QAC8B;CAClC,OAAO,MAAM,WAAW,KAAK,IAAI,WAAY,EAAE;CAC/C,MAAML,QAAa,GAAG,MAAM;CAC5B,OAAO,QAAQ,QAAQ,KAAK;AAmE9B;AAEA,eAAsB,aACpB,MACA,WACe;CAEf,MAAM,uBAAuB,yFADH,UAAU,OACoG,0BAA0B,KAAK,UACrK,SACF,EAAE;CACF,MAAM,MAAM,MAAMM,qBAChB,GAAG,QACH,oBACF;;CAEA,IAAI,KAAK;EACP,MAAM,eAAe,IAAI;EACzB,OAAO,MAAM,EAAE,aAAa,GAAG,8BAA8B,KAAK,EAAE;CACtE;AACF;;AAGA,SAAgB,aACd,MACA,YACe;CAEf,OAAO,QAAQ,QAAQ;AACzB;;AAGA,SAAgB,UAAU,QAAuC;CAE/D,OAAO,QAAQ,QAAQ,IAAI;AAC7B;;AAGA,SAAgB,YACd,MACmC;CAEnC,OAAO,QAAQ,QAAQ,IAAI;AAC7B;;AAGA,SAAgB,eAAiC;CAE/C,OAAO,QAAQ,QAAQ,CAAC,CAAC;AAC3B;;AAGA,SAAgB,mBAAmB,QAA+B;CAEhE,OAAO,QAAQ,QAAQ;AACzB;;AAGA,SAAgB,YAAY,WAAmB,QAA+B;CAC5E,OAAO,QAAQ,QAAQ;AACzB;;AAIA,SAAgB,gBAAgB,YAA2C;CACzE,OAAO,MAAM,mBAAmB,WAAW,EAAE;CAC7C,OAAO,MACL,mFACF;CACA,OAAO,QAAQ,QAAQ,QAAQ;AACjC;;AAGA,SAAgB,qBACd,YACA,SAC8B;CAC9B,OAAO,MAAM,wBAAwB,WAAW,YAAY,QAAQ,EAAE;CACtE,OAAO,MACL,0EACF;CACA,OAAO,QAAQ,QAAQ,IAAI;AAC7B;;AAGA,SAAgB,gBAAgB,MAAyC;CACvE,OAAO,QAAQ,QAAQ;AACzB;AAEA,eAAsB,cAAc,EAClC,QACA,OACA,WACwC;CACxC,OAAO,MAAM,iBAAiB,OAAO,IAAI,MAAO,WAAW;CAC3D,MAAM,SAAS,QAAQ,OAAO,MAAM,QAAQ;CAC5C,MAAM,OAAO,GAAG,SAAS,SAAS,OAAO;CACzC,IAAI;CACJ,IAAI;EACF,qBAAqB,MAAMC,cAAqB,GAAG,QAAQ;CAC7D,SAAS,KAAK;EACZ,OAAO,MAAM,EAAE,IAAI,GAAG,gCAAgC;EACtD,OAAO;CACT;CAEA,IAAI,YAAgC,KAAA;CACpC,IAAI,uBAAuB;CAE3B,IAAI,CAAC,oBAAoB,4BACvB,OAAO;CAGT,KAAK,MAAM,cAAc,mBAAmB,4BAA4B;EACtE,IAAI,CAAC,YAAY,UACf;EAEF,MAAM,sBAAsB,WAAW,SAAS,EAAE,CAAC;EACnD,KACG,SAAS,qBAAqB,WAAW,MAAM,OAAO,QACtD,CAAC,SAAS,wBAAwB,MACnC;GACA,YAAY,WAAW,SAAS,EAAE,CAAC;GACnC,uBAAuB,wBAAwB;GAC/C;EACF;CACF;CAEA,IAAI,CAAC,WAAW;EAEd,MAAM,UAAS,MADG,UAAU,EAAA,CACT,QAAQ,SAAS,KAAK,WAAW,MAAM;EAE1D,IAAI,CAAC,OAAO,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,mBACxC,OAAO;EAGT,MAAMC,gBACJ,GAAG,UACH,OAAO,YACP,MACA,OAAO,EAAE,CAAC,mBACV,OAAO,EAAE,CAAC,YACZ;EACA,OAAO,KACL;GAAE,YAAY,OAAO;GAAY,MAAM;GAAQ;EAAM,GACrD,eACF;CACF,OAAO,IAAI,wBAAwB,WAAW;EAC5C,MAAMC,cAAqB,WAAW,IAAI;EAE1C,OAAO,MACL;GAAE,YAAY,OAAO;GAAY,MAAM;GAAQ;EAAM,GACrD,iBACF;CACF,OACE,OAAO,MACL;EAAE,YAAY,OAAO;EAAY,MAAM;EAAQ;CAAM,GACrD,+BACF;CAGF,OAAO;AACT;AAEA,eAAsB,qBACpB,cACe;CACf,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,MACJ,aAAa,SAAS,aAClB,aAAa,QACb,aAAa;CACnB,OAAO,MAAM,qBAAqB,IAAI,QAAQ,KAAK,YAAY;CAE/D,IAAI;CACJ,IAAI;EACF,qBAAqB,MAAMF,cAAqB,GAAG,MAAM;CAC3D,SAAS,KAAK;EACZ,OAAO,MAAM,EAAE,IAAI,GAAG,gCAAgC;EACtD;CACF;CAEA,IAAI,CAAC,oBAAoB,4BAA4B;EACnD,OAAO,MAAM,sCAAsC;EACnD;CACF;CAEA,IAAI;CACJ,KAAK,MAAM,cAAc,mBAAmB,4BAA4B;EACtE,IAAI,CAAC,YAAY,UAAU;GACzB,OAAO,MACL,4DACF;GACA;EACF;EAEA,KAAK,MAAM,WAAW,WAAW;;EAE/B,KACG,aAAa,SAAS,cACrB,QAAQ,SAAS,WAAW,OAAO,aAAa,MAAM,KAAK,OAC3D,QACD,aAAa,SAAS,gBACrB,aAAa,YAAY,QAAQ,SAAS,KAAK,GACjD;GACA,oBAAoB,QAAQ;GAC5B;EACF;;EAGF,IAAI,mBAAmB;GACrB,MAAMG,cAAqB,iBAAiB;GAC5C,OAAO,MAAM,YAAY,IAAI,WAAW,KAAK,aAAa;GAC1D;EACF;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["client.listRepositories","client.getRepositoryInfo","client.getCodeCommitUrl","git.initRepo","client.listPullRequests","client.getPr","client.getFile","client.createPr","client.updatePrDescription","client.updatePrTitle","client.updatePrStatus","client.createPrApprovalRule","client.getPrComments","client.createPrComment","client.updateComment","client.deleteComment"],"sources":["../../../../lib/modules/platform/codecommit/index.ts"],"sourcesContent":["import { Buffer } from 'node:buffer';\nimport type {\n GetCommentsForPullRequestOutput,\n ListRepositoriesOutput,\n} from '@aws-sdk/client-codecommit';\nimport { PullRequestStatusEnum } from '@aws-sdk/client-codecommit';\nimport {\n PLATFORM_BAD_CREDENTIALS,\n REPOSITORY_EMPTY,\n REPOSITORY_NOT_FOUND,\n} from '../../../constants/error-messages.ts';\nimport { logger } from '../../../logger/index.ts';\nimport type { BranchStatus, PrState } from '../../../types/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { parseJson } from '../../../util/common.ts';\nimport * as git from '../../../util/git/index.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { sanitize } from '../../../util/sanitize.ts';\nimport type {\n BranchStatusConfig,\n CreatePRConfig,\n EnsureCommentConfig,\n EnsureCommentRemovalConfig,\n EnsureIssueConfig,\n EnsureIssueResult,\n FindPRConfig,\n Issue,\n MergePRConfig,\n PlatformParams,\n PlatformResult,\n Pr,\n RepoParams,\n RepoResult,\n UpdatePrConfig,\n} from '../types.ts';\nimport { getNewBranchName, repoFingerprint } from '../util.ts';\nimport { smartTruncate } from '../utils/pr-body.ts';\nimport * as client from './codecommit-client.ts';\n\nexport interface CodeCommitPr extends Pr {\n body: string;\n destinationCommit: string;\n sourceCommit: string;\n}\n\ninterface Config {\n repository?: string;\n defaultBranch?: string;\n region?: string;\n prList?: CodeCommitPr[];\n}\n\nexport const id = 'codecommit';\nexport const experimental = true;\n\nconst platformConfig = {\n endpoint: 'https://git-codecommit.us-east-1.amazonaws.com',\n};\n\nlet config: Config = {} as any;\n\nexport async function initPlatform({\n endpoint,\n username,\n password,\n token: awsToken,\n}: PlatformParams): Promise<PlatformResult> {\n const accessKeyId = username;\n const secretAccessKey = password;\n const env = process.env;\n let region: string | undefined;\n\n if (accessKeyId) {\n env.AWS_ACCESS_KEY_ID = accessKeyId;\n }\n if (secretAccessKey) {\n env.AWS_SECRET_ACCESS_KEY = secretAccessKey;\n }\n if (awsToken) {\n env.AWS_SESSION_TOKEN = awsToken;\n }\n\n if (endpoint) {\n const regionReg = regEx(/.*codecommit\\.(?<region>.+)\\.amazonaws\\.com/);\n const codeCommitMatch = regionReg.exec(endpoint);\n region = codeCommitMatch?.groups?.region;\n if (region) {\n env.AWS_REGION = region;\n } else {\n logger.warn(\"Can't parse region, make sure your endpoint is correct\");\n }\n }\n\n // If any of the below fails, it will throw an exception stopping the program.\n client.buildCodeCommitClient();\n // To check if we have permission to codecommit, throws exception if failed.\n await client.listRepositories();\n\n platformConfig.endpoint =\n endpoint ??\n `https://git-codecommit.${env.AWS_REGION ?? 'us-east-1'}.amazonaws.com/`;\n\n const platformResult: PlatformResult = {\n endpoint: platformConfig.endpoint,\n };\n return platformResult;\n}\n\nexport async function initRepo({\n repository,\n}: RepoParams): Promise<RepoResult> {\n logger.debug(`initRepo(\"${repository}\")`);\n\n config = { repository } as Config;\n\n let repo;\n try {\n repo = await client.getRepositoryInfo(repository);\n } catch (err) {\n logger.error({ err }, 'Could not find repository');\n throw new Error(REPOSITORY_NOT_FOUND);\n }\n\n if (!repo?.repositoryMetadata) {\n logger.error({ repository }, 'Could not find repository');\n throw new Error(REPOSITORY_NOT_FOUND);\n }\n logger.debug({ repositoryDetails: repo }, 'Repository details');\n const metadata = repo.repositoryMetadata;\n\n const url = client.getCodeCommitUrl(metadata, repository);\n try {\n await git.initRepo({\n url,\n });\n } catch (err) {\n logger.debug({ err }, 'Failed to git init');\n throw new Error(PLATFORM_BAD_CREDENTIALS);\n }\n\n if (!metadata.defaultBranch || !metadata.repositoryId) {\n logger.debug('Repo is empty');\n throw new Error(REPOSITORY_EMPTY);\n }\n\n const defaultBranch = metadata.defaultBranch;\n config.defaultBranch = defaultBranch;\n logger.debug(`${repository} default branch = ${defaultBranch}`);\n\n return {\n repoFingerprint: repoFingerprint(\n metadata.repositoryId,\n platformConfig.endpoint,\n ),\n defaultBranch,\n isFork: false,\n };\n}\n\nexport async function getPrList(): Promise<CodeCommitPr[]> {\n logger.debug('getPrList()');\n\n if (config.prList) {\n return config.prList;\n }\n\n const listPrsResponse = await client.listPullRequests(config.repository!);\n const fetchedPrs: CodeCommitPr[] = [];\n\n if (listPrsResponse && !listPrsResponse.pullRequestIds) {\n return fetchedPrs;\n }\n\n const prIds = coerceArray(listPrsResponse.pullRequestIds);\n\n for (const prId of prIds) {\n const prRes = await client.getPr(prId);\n\n if (!prRes?.pullRequest) {\n continue;\n }\n const prInfo = prRes.pullRequest;\n const pr: CodeCommitPr = {\n targetBranch: prInfo.pullRequestTargets![0].destinationReference!,\n sourceBranch: prInfo.pullRequestTargets![0].sourceReference!,\n destinationCommit: prInfo.pullRequestTargets![0].destinationCommit!,\n sourceCommit: prInfo.pullRequestTargets![0].sourceCommit!,\n state:\n prInfo.pullRequestStatus === PullRequestStatusEnum.OPEN\n ? 'open'\n : 'closed',\n number: Number.parseInt(prId, 10),\n title: prInfo.title!,\n body: prInfo.description!,\n createdAt: prInfo.creationDate?.toISOString(),\n };\n fetchedPrs.push(pr);\n }\n\n config.prList = fetchedPrs;\n\n logger.debug(`Retrieved Pull Requests, count: ${fetchedPrs.length}`);\n return fetchedPrs;\n}\n\nexport async function findPr({\n branchName,\n prTitle,\n state = 'all',\n}: FindPRConfig): Promise<CodeCommitPr | null> {\n let prsFiltered: CodeCommitPr[] = [];\n try {\n const prs = await getPrList();\n const refsHeadBranchName = getNewBranchName(branchName);\n prsFiltered = prs.filter(\n (item) => item.sourceBranch === refsHeadBranchName,\n );\n\n if (prTitle) {\n prsFiltered = prsFiltered.filter(\n (item) => item.title.toUpperCase() === prTitle.toUpperCase(),\n );\n }\n\n switch (state) {\n case 'all':\n break;\n case '!open':\n prsFiltered = prsFiltered.filter((item) => item.state !== 'open');\n break;\n default:\n prsFiltered = prsFiltered.filter((item) => item.state === 'open');\n break;\n }\n } catch (err) {\n logger.error({ err }, 'findPr error');\n }\n if (prsFiltered.length === 0) {\n return null;\n }\n return prsFiltered[0];\n}\n\nexport async function getBranchPr(\n branchName: string,\n): Promise<CodeCommitPr | null> {\n logger.debug(`getBranchPr(${branchName})`);\n const existingPr = await findPr({\n branchName,\n state: 'open',\n });\n return existingPr ? getPr(existingPr.number) : null;\n}\n\nexport async function getPr(\n pullRequestId: number,\n): Promise<CodeCommitPr | null> {\n logger.debug(`getPr(${pullRequestId})`);\n const prRes = await client.getPr(`${pullRequestId}`);\n\n if (!prRes?.pullRequest) {\n return null;\n }\n\n const prInfo = prRes.pullRequest;\n let prState: PrState;\n if (prInfo.pullRequestTargets![0].mergeMetadata?.isMerged) {\n prState = 'merged';\n } else {\n prState =\n prInfo.pullRequestStatus === PullRequestStatusEnum.OPEN\n ? 'open'\n : 'closed';\n }\n\n return {\n sourceBranch: prInfo.pullRequestTargets![0].sourceReference!,\n sourceCommit: prInfo.pullRequestTargets![0].sourceCommit!,\n state: prState,\n number: pullRequestId,\n title: prInfo.title!,\n targetBranch: prInfo.pullRequestTargets![0].destinationReference!,\n destinationCommit: prInfo.pullRequestTargets![0].destinationCommit!,\n body: prInfo.description!,\n };\n}\n\nexport async function getRepos(): Promise<string[]> {\n logger.debug('Autodiscovering AWS CodeCommit repositories');\n\n let reposRes: ListRepositoriesOutput;\n try {\n reposRes = await client.listRepositories();\n //todo do we need pagination? maximum number of repos is 1000 without pagination, also the same for free account\n } catch (err) {\n logger.error({ err }, 'Could not retrieve repositories');\n return [];\n }\n\n const res: string[] = [];\n\n const repoNames = coerceArray(reposRes?.repositories);\n\n for (const repo of repoNames) {\n // v8 ignore else -- TODO: add test #40625\n if (repo.repositoryName) {\n res.push(repo.repositoryName);\n }\n }\n\n return res;\n}\n\nexport function massageMarkdown(input: string): string {\n // Remove any HTML we use\n return input\n .replace(\n 'you tick the rebase/retry checkbox',\n 'PR is renamed to start with \"rebase!\"',\n )\n .replace(\n 'checking the rebase/retry box above',\n 'renaming the PR to start with \"rebase!\"',\n )\n .replace(regEx(/<\\/?summary>/g), '**')\n .replace(regEx(/<\\/?details>/g), '')\n .replace(regEx(`\\n---\\n\\n.*?<!-- rebase-check -->.*?\\n`), '')\n .replace(regEx(/\\]\\(\\.\\.\\/issues\\//g), '](#')\n .replace(regEx(/\\]\\(\\.\\.\\/pull\\//g), '](../../pull-requests/')\n .replace(\n regEx(/(?<hiddenComment><!--renovate-(?:debug|config-hash):.*?-->)/g),\n '[//]: # ($<hiddenComment>)',\n );\n}\n\n/**\n * Unsed, no Dashboard\n */\nexport function maxBodyLength(): number {\n return Infinity;\n}\n\nexport async function getJsonFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n): Promise<any> {\n const raw = await getRawFile(fileName, repoName, branchOrTag);\n return parseJson(raw, fileName);\n}\n\nexport async function getRawFile(\n fileName: string,\n repoName?: string,\n branchOrTag?: string,\n): Promise<string | null> {\n const fileRes = await client.getFile(\n repoName ?? config.repository,\n fileName,\n branchOrTag,\n );\n if (!fileRes?.fileContent) {\n return null;\n }\n const buf = Buffer.from(fileRes.fileContent);\n return buf.toString();\n}\n\nconst AMAZON_MAX_BODY_LENGTH = 10239;\n\nexport async function createPr({\n sourceBranch,\n targetBranch,\n prTitle: title,\n prBody: body,\n}: CreatePRConfig): Promise<CodeCommitPr> {\n const description = smartTruncate(sanitize(body), AMAZON_MAX_BODY_LENGTH);\n\n const prCreateRes = await client.createPr(\n title,\n sanitize(description),\n sourceBranch,\n targetBranch,\n config.repository,\n );\n\n if (\n !prCreateRes.pullRequest?.title ||\n !prCreateRes.pullRequest?.pullRequestId ||\n !prCreateRes.pullRequest?.description ||\n !prCreateRes.pullRequest?.pullRequestTargets?.length\n ) {\n throw new Error('Could not create pr, missing PR info');\n }\n\n return {\n number: Number.parseInt(prCreateRes.pullRequest.pullRequestId, 10),\n state: 'open',\n title: prCreateRes.pullRequest.title,\n sourceBranch,\n targetBranch,\n sourceCommit: prCreateRes.pullRequest.pullRequestTargets[0].sourceCommit!,\n destinationCommit:\n prCreateRes.pullRequest.pullRequestTargets[0].destinationCommit!,\n sourceRepo: config.repository,\n body: prCreateRes.pullRequest.description,\n };\n}\n\nexport async function updatePr({\n number: prNo,\n prTitle: title,\n prBody: body,\n state,\n}: UpdatePrConfig): Promise<void> {\n logger.debug(`updatePr(${prNo}, ${title}, body)`);\n\n let cachedPr: CodeCommitPr | undefined = undefined;\n const cachedPrs = config.prList ?? [];\n for (const p of cachedPrs) {\n // v8 ignore else -- TODO: add test #40625\n if (p.number === prNo) {\n cachedPr = p;\n }\n }\n\n // v8 ignore else -- TODO: add test #40625\n if (body && cachedPr?.body !== body) {\n await client.updatePrDescription(\n `${prNo}`,\n smartTruncate(sanitize(body), AMAZON_MAX_BODY_LENGTH),\n );\n }\n\n // v8 ignore else -- TODO: add test #40625\n if (title && cachedPr?.title !== title) {\n await client.updatePrTitle(`${prNo}`, title);\n }\n\n const prStatusInput =\n state === 'closed'\n ? PullRequestStatusEnum.CLOSED\n : PullRequestStatusEnum.OPEN;\n // v8 ignore else -- TODO: add test #40625\n if (cachedPr?.state !== prStatusInput) {\n try {\n await client.updatePrStatus(`${prNo}`, prStatusInput);\n } catch {\n // safety check\n // do nothing, it's ok to fail sometimes when trying to update from open to open or from closed to closed.\n }\n }\n}\n\n// Auto-Merge not supported currently.\n/* v8 ignore next */\nexport async function mergePr({\n branchName,\n id: prNo,\n}: MergePRConfig): Promise<boolean> {\n logger.debug(`mergePr(${prNo}, ${branchName!})`);\n await client.getPr(`${prNo}`);\n return Promise.resolve(false);\n //\n // /* v8 ignore next */\n // if (!prOut) {\n // return false;\n // }\n // const pReq = prOut.pullRequest;\n // const targets = pReq?.pullRequestTargets;\n //\n // /* v8 ignore next */\n // if (!targets) {\n // return false;\n // }\n //\n // if (strategy === 'rebase') {\n // logger.warn('CodeCommit does not support a \"rebase\" strategy.');\n // return false;\n // }\n //\n // try {\n // if (strategy === 'auto' || strategy === 'squash') {\n // await client.squashMerge(\n // targets[0].repositoryName!,\n // targets[0].sourceReference!,\n // targets[0].destinationReference!,\n // pReq?.title\n // );\n // } else if (strategy === 'fast-forward') {\n // await client.fastForwardMerge(\n // targets[0].repositoryName!,\n // targets[0].sourceReference!,\n // targets[0].destinationReference!\n // );\n // } else {\n // logger.debug(`unsupported strategy`);\n // return false;\n // }\n // } catch (err) {\n // logger.debug({ err }, `PR merge error`);\n // logger.info({ pr: prNo }, 'PR automerge failed');\n // return false;\n // }\n //\n // logger.trace(`Updating PR ${prNo} to status ${PullRequestStatusEnum.CLOSED}`);\n //\n // try {\n // const response = await client.updatePrStatus(\n // `${prNo}`,\n // PullRequestStatusEnum.CLOSED\n // );\n // const isClosed =\n // response.pullRequest?.pullRequestStatus === PullRequestStatusEnum.CLOSED;\n //\n // if (!isClosed) {\n // logger.warn(\n // {\n // pullRequestId: prNo,\n // status: response.pullRequest?.pullRequestStatus,\n // },\n // `Expected PR to have status`\n // );\n // }\n // return true;\n // } catch (err) {\n // logger.debug({ err }, 'Failed to set the PR as Closed.');\n // return false;\n // }\n}\n\nexport async function addReviewers(\n prNo: number,\n reviewers: string[],\n): Promise<void> {\n const numberOfApprovers = reviewers.length;\n const approvalRuleContents = `{\"Version\":\"2018-11-08\",\"Statements\": [{\"Type\": \"Approvers\",\"NumberOfApprovalsNeeded\":${numberOfApprovers},\"ApprovalPoolMembers\": ${JSON.stringify(\n reviewers,\n )}}]}`;\n const res = await client.createPrApprovalRule(\n `${prNo}`,\n approvalRuleContents,\n );\n // v8 ignore else -- TODO: add test #40625\n if (res) {\n const approvalRule = res.approvalRule;\n logger.debug({ approvalRule }, `Approval Rule Added to PR #${prNo}:`);\n }\n}\n\n/* v8 ignore next */\nexport function addAssignees(\n _iid: number,\n _assignees: string[],\n): Promise<void> {\n // CodeCommit does not support adding reviewers\n return Promise.resolve();\n}\n\n/* v8 ignore next */\nexport function findIssue(_title: string): Promise<Issue | null> {\n // CodeCommit does not have issues\n return Promise.resolve(null);\n}\n\n/* v8 ignore next */\nexport function ensureIssue(\n _cfg: EnsureIssueConfig,\n): Promise<EnsureIssueResult | null> {\n // CodeCommit does not have issues\n return Promise.resolve(null);\n}\n\n/* v8 ignore next */\nexport function getIssueList(): Promise<Issue[]> {\n // CodeCommit does not have issues\n return Promise.resolve([]);\n}\n\n/* v8 ignore next */\nexport function ensureIssueClosing(_title: string): Promise<void> {\n // CodeCommit does not have issues\n return Promise.resolve();\n}\n\n/* v8 ignore next */\nexport function deleteLabel(_prNumber: number, _label: string): Promise<void> {\n return Promise.resolve();\n}\n\n// Returns the combined status for a branch.\n/* v8 ignore next */\nexport function getBranchStatus(branchName: string): Promise<BranchStatus> {\n logger.debug(`getBranchStatus(${branchName})`);\n logger.debug(\n 'returning branch status yellow, because getBranchStatus isnt supported on aws yet',\n );\n return Promise.resolve('yellow');\n}\n\n/* v8 ignore next */\nexport function getBranchStatusCheck(\n branchName: string,\n context: string,\n): Promise<BranchStatus | null> {\n logger.debug(`getBranchStatusCheck(${branchName}, context=${context})`);\n logger.debug(\n 'returning null, because getBranchStatusCheck is not supported on aws yet',\n );\n return Promise.resolve(null);\n}\n\n/* v8 ignore next */\nexport function setBranchStatus(_cfg: BranchStatusConfig): Promise<void> {\n return Promise.resolve();\n}\n\nexport async function ensureComment({\n number,\n topic,\n content,\n}: EnsureCommentConfig): Promise<boolean> {\n logger.debug(`ensureComment(${number}, ${topic!}, content)`);\n const header = topic ? `### ${topic}\\n\\n` : '';\n const body = `${header}${sanitize(content)}`;\n let prCommentsResponse: GetCommentsForPullRequestOutput;\n try {\n prCommentsResponse = await client.getPrComments(`${number}`);\n } catch (err) {\n logger.debug({ err }, 'Unable to retrieve pr comments');\n return false;\n }\n\n let commentId: string | undefined = undefined;\n let commentNeedsUpdating = false;\n\n if (!prCommentsResponse?.commentsForPullRequestData) {\n return false;\n }\n\n for (const commentObj of prCommentsResponse.commentsForPullRequestData) {\n if (!commentObj?.comments) {\n continue;\n }\n const firstCommentContent = commentObj.comments[0].content;\n if (\n (topic && firstCommentContent?.startsWith(header)) === true ||\n (!topic && firstCommentContent === body)\n ) {\n commentId = commentObj.comments[0].commentId;\n commentNeedsUpdating = firstCommentContent !== body;\n break;\n }\n }\n\n if (!commentId) {\n const prs = await getPrList();\n const thisPr = prs.filter((item) => item.number === number);\n\n if (!thisPr[0].sourceCommit || !thisPr[0].destinationCommit) {\n return false;\n }\n\n await client.createPrComment(\n `${number}`,\n config.repository,\n body,\n thisPr[0].destinationCommit,\n thisPr[0].sourceCommit,\n );\n logger.info(\n { repository: config.repository, prNo: number, topic },\n 'Comment added',\n );\n } else if (commentNeedsUpdating && commentId) {\n await client.updateComment(commentId, body);\n\n logger.debug(\n { repository: config.repository, prNo: number, topic },\n 'Comment updated',\n );\n } else {\n logger.debug(\n { repository: config.repository, prNo: number, topic },\n 'Comment is already up-to-date',\n );\n }\n\n return true;\n}\n\nexport async function ensureCommentRemoval(\n removeConfig: EnsureCommentRemovalConfig,\n): Promise<void> {\n const { number: prNo } = removeConfig;\n const key =\n removeConfig.type === 'by-topic'\n ? removeConfig.topic\n : removeConfig.content;\n logger.debug(`Ensuring comment \"${key}\" in #${prNo} is removed`);\n\n let prCommentsResponse: GetCommentsForPullRequestOutput;\n try {\n prCommentsResponse = await client.getPrComments(`${prNo}`);\n } catch (err) {\n logger.debug({ err }, 'Unable to retrieve pr comments');\n return;\n }\n\n if (!prCommentsResponse?.commentsForPullRequestData) {\n logger.debug('commentsForPullRequestData not found');\n return;\n }\n\n let commentIdToRemove: string | undefined;\n for (const commentObj of prCommentsResponse.commentsForPullRequestData) {\n if (!commentObj?.comments) {\n logger.debug(\n 'comments object not found under commentsForPullRequestData',\n );\n continue;\n }\n\n for (const comment of commentObj.comments) {\n // v8 ignore else -- TODO: add test #40625\n if (\n (removeConfig.type === 'by-topic' &&\n comment.content?.startsWith(`### ${removeConfig.topic}\\n\\n`)) ===\n true ||\n (removeConfig.type === 'by-content' &&\n removeConfig.content === comment.content?.trim())\n ) {\n commentIdToRemove = comment.commentId;\n break;\n }\n }\n // v8 ignore else -- TODO: add test #40625\n if (commentIdToRemove) {\n await client.deleteComment(commentIdToRemove);\n logger.debug(`comment \"${key}\" in PR #${prNo} was removed`);\n break;\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","names":[],"sources":["../../../../lib/modules/platform/gitlab/http.ts"],"sourcesContent":["import { isEmptyArray } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport { GitlabHttp } from '../../../util/http/gitlab.ts';\nimport type { GitLabUser, GitlabUserStatus } from './types.ts';\n\nexport const gitlabApi = new GitlabHttp();\n\nexport async function getUserID(username: string): Promise<number> {\n const userInfo = (\n await gitlabApi.getJsonUnchecked<{ id: number }[]>(\n `users?username=${username}`,\n )\n ).body;\n\n if (isEmptyArray(userInfo)) {\n throw new Error(\n `User ID for the username: ${username} could not be found.`,\n );\n }\n\n return userInfo[0].id;\n}\n\nasync function getMembers(group: string): Promise<GitLabUser[]> {\n const groupEncoded = encodeURIComponent(group);\n return (\n await gitlabApi.getJsonUnchecked<GitLabUser[]>(\n `groups/${groupEncoded}/members`,\n )\n ).body;\n}\n\nexport async function getMemberUserIDs(group: string): Promise<number[]> {\n try {\n const members = await getMembers(group);\n return members.map((u) => u.id);\n } catch (err) {\n logger.once.warn(\n { group, errorMessage: err.message },\n
|
|
1
|
+
{"version":3,"file":"http.js","names":[],"sources":["../../../../lib/modules/platform/gitlab/http.ts"],"sourcesContent":["import { isEmptyArray } from '@sindresorhus/is';\nimport { logger } from '../../../logger/index.ts';\nimport { GitlabHttp } from '../../../util/http/gitlab.ts';\nimport type { GitLabUser, GitlabUserStatus } from './types.ts';\n\nexport const gitlabApi = new GitlabHttp();\n\nexport async function getUserID(username: string): Promise<number> {\n const userInfo = (\n await gitlabApi.getJsonUnchecked<{ id: number }[]>(\n `users?username=${username}`,\n )\n ).body;\n\n if (isEmptyArray(userInfo)) {\n throw new Error(\n `User ID for the username: ${username} could not be found.`,\n );\n }\n\n return userInfo[0].id;\n}\n\nasync function getMembers(group: string): Promise<GitLabUser[]> {\n const groupEncoded = encodeURIComponent(group);\n return (\n await gitlabApi.getJsonUnchecked<GitLabUser[]>(\n `groups/${groupEncoded}/members`,\n )\n ).body;\n}\n\nexport async function getMemberUserIDs(group: string): Promise<number[]> {\n try {\n const members = await getMembers(group);\n return members.map((u) => u.id);\n } catch (err) {\n logger.once.warn(\n { group, errorMessage: err.message },\n 'Unable to fetch user IDs for group members',\n );\n return [];\n }\n}\n\nexport async function getMemberUsernames(group: string): Promise<string[]> {\n const members = await getMembers(group);\n return members.map((u) => u.username);\n}\n\nexport async function isUserBusy(user: string): Promise<boolean> {\n try {\n const url = `/users/${user}/status`;\n const userStatus = (await gitlabApi.getJsonUnchecked<GitlabUserStatus>(url))\n .body;\n return userStatus.availability === 'busy';\n } catch (err) {\n logger.warn({ err }, 'Failed to get user status');\n return false;\n }\n}\n"],"mappings":";;;;AAKA,MAAa,YAAY,IAAI,WAAW;AAExC,eAAsB,UAAU,UAAmC;CACjE,MAAM,YACJ,MAAM,UAAU,iBACd,kBAAkB,UACpB,EAAA,CACA;CAEF,IAAI,aAAa,QAAQ,GACvB,MAAM,IAAI,MACR,6BAA6B,SAAS,qBACxC;CAGF,OAAO,SAAS,EAAE,CAAC;AACrB;AAEA,eAAe,WAAW,OAAsC;CAC9D,MAAM,eAAe,mBAAmB,KAAK;CAC7C,QACE,MAAM,UAAU,iBACd,UAAU,aAAa,SACzB,EAAA,CACA;AACJ;AAEA,eAAsB,iBAAiB,OAAkC;CACvE,IAAI;EAEF,QAAO,MADe,WAAW,KAAK,EAAA,CACvB,KAAK,MAAM,EAAE,EAAE;CAChC,SAAS,KAAK;EACZ,OAAO,KAAK,KACV;GAAE;GAAO,cAAc,IAAI;EAAQ,GACnC,4CACF;EACA,OAAO,CAAC;CACV;AACF;AAEA,eAAsB,mBAAmB,OAAkC;CAEzE,QAAO,MADe,WAAW,KAAK,EAAA,CACvB,KAAK,MAAM,EAAE,QAAQ;AACtC;AAEA,eAAsB,WAAW,MAAgC;CAC/D,IAAI;EACF,MAAM,MAAM,UAAU,KAAK;EAG3B,QAFoB,MAAM,UAAU,iBAAmC,GAAG,EAAA,CACvE,KACe,iBAAiB;CACrC,SAAS,KAAK;EACZ,OAAO,KAAK,EAAE,IAAI,GAAG,2BAA2B;EAChD,OAAO;CACT;AACF"}
|