From 0bdfbc57b4cb3c82ae8a34eeed8c8b90358cdc2f Mon Sep 17 00:00:00 2001 From: Sergei Shmakov Date: Wed, 3 Sep 2025 16:35:28 +0200 Subject: [PATCH] Unifies autolink enrichment keys for integrations in order to avoid referencing the exact integration type outside of integratin class. Updates the autolink enrichment workflow to consistently use a pair of values (id and key) when resolving issues or pull requests across integrations. This removes provider-specific logic for constructing enrichment keys and centralizes the approach, simplifying maintenance and reducing errors when linking to external systems. Renames and refactors relevant methods in integration classes to reflect this unified signature. Enhances consistency and clarity in how autolinked items are identified and retrieved across supported providers. --- .gitignore | 1 + src/autolinks/autolinksProvider.ts | 28 +++++++++---------- src/plus/integrations/models/integration.ts | 14 +++++----- .../integrations/providers/azureDevOps.ts | 4 +-- .../providers/bitbucket-server.ts | 4 +-- src/plus/integrations/providers/bitbucket.ts | 4 +-- src/plus/integrations/providers/github.ts | 4 +-- src/plus/integrations/providers/gitlab.ts | 4 +-- src/plus/integrations/providers/jira.ts | 6 ++-- src/plus/integrations/providers/linear.ts | 4 +-- 10 files changed, 36 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index 01c86a307e510..ced5e09ef008d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ images/settings gitlens-*.vsix product.json tsconfig*.tsbuildinfo +localdev*.instructions.md diff --git a/src/autolinks/autolinksProvider.ts b/src/autolinks/autolinksProvider.ts index 455cf1523482c..547a03bb5c84d 100644 --- a/src/autolinks/autolinksProvider.ts +++ b/src/autolinks/autolinksProvider.ts @@ -2,7 +2,6 @@ import type { ConfigurationChangeEvent } from 'vscode'; import { Disposable } from 'vscode'; import { GlyphChars } from '../constants'; import type { IntegrationIds } from '../constants.integrations'; -import { IssuesCloudHostIntegrationId } from '../constants.integrations'; import type { Container } from '../container'; import type { GitRemote } from '../git/models/remote'; import type { RemoteProvider, RemoteProviderId } from '../git/remotes/remoteProvider'; @@ -177,16 +176,11 @@ export class AutolinksProvider implements Disposable { return getAutolinks(message, refsets); } - getAutolinkEnrichableId(autolink: Autolink): string { - // TODO: this should return linking key for all types of providers: such as TST-123 or #89 or PR 89 (or a pair: key+id). - // Each provider should form whatever ID they need in their specific getIssueOrPullRequest() method. - switch (autolink.provider?.id) { - case IssuesCloudHostIntegrationId.Jira: - case IssuesCloudHostIntegrationId.Linear: - return `${autolink.prefix}${autolink.id}`; - default: - return autolink.id; - } + getAutolinkEnrichableId(autolink: Autolink): { id: string; key: string } { + return { + id: autolink.id, + key: `${autolink.prefix}${autolink.id}`, + }; } async getEnrichedAutolinks( @@ -258,15 +252,19 @@ export class AutolinksProvider implements Disposable { integration != null && integrationId === integration.id && link.provider?.domain === integration.domain - ? integration.getIssueOrPullRequest( + ? integration.getLinkedIssueOrPullRequest( link.descriptor ?? remote.provider.repoDesc, this.getAutolinkEnrichableId(link), { type: link.type }, ) : link.descriptor != null - ? linkIntegration?.getIssueOrPullRequest(link.descriptor, this.getAutolinkEnrichableId(link), { - type: link.type, - }) + ? linkIntegration?.getLinkedIssueOrPullRequest( + link.descriptor, + this.getAutolinkEnrichableId(link), + { + type: link.type, + }, + ) : undefined; enrichedAutolinks.set(id, [issueOrPullRequestPromise, link]); } diff --git a/src/plus/integrations/models/integration.ts b/src/plus/integrations/models/integration.ts index 249a3cd25ac1c..fc7294407158b 100644 --- a/src/plus/integrations/models/integration.ts +++ b/src/plus/integrations/models/integration.ts @@ -499,9 +499,9 @@ export abstract class IntegrationBase< ): Promise; @debug() - async getIssueOrPullRequest( + async getLinkedIssueOrPullRequest( resource: T, - id: string, + link: { id: string; key: string }, options?: { expiryOverride?: boolean | number; type?: IssueOrPullRequestType }, ): Promise { const scope = getLogScope(); @@ -512,17 +512,17 @@ export abstract class IntegrationBase< await this.refreshSessionIfExpired(scope); const issueOrPR = this.container.cache.getIssueOrPullRequest( - id, + link.key, options?.type, resource, this, () => ({ value: (async () => { try { - const result = await this.getProviderIssueOrPullRequest( + const result = await this.getProviderLinkedIssueOrPullRequest( this._session!, resource, - id, + link, options?.type, ); this.resetRequestExceptionCount('getIssueOrPullRequest'); @@ -538,10 +538,10 @@ export abstract class IntegrationBase< return issueOrPR; } - protected abstract getProviderIssueOrPullRequest( + protected abstract getProviderLinkedIssueOrPullRequest( session: ProviderAuthenticationSession, resource: T, - id: string, + link: { id: string; key: string }, type: undefined | IssueOrPullRequestType, ): Promise; diff --git a/src/plus/integrations/providers/azureDevOps.ts b/src/plus/integrations/providers/azureDevOps.ts index abd8dee6bdb1d..60f08efe7d2f5 100644 --- a/src/plus/integrations/providers/azureDevOps.ts +++ b/src/plus/integrations/providers/azureDevOps.ts @@ -259,10 +259,10 @@ export abstract class AzureDevOpsIntegrationBase< return Promise.resolve(undefined); } - protected override async getProviderIssueOrPullRequest( + protected override async getProviderLinkedIssueOrPullRequest( { accessToken }: AuthenticationSession, repo: AzureRepositoryDescriptor, - id: string, + { id }: { id: string; key: string }, type: undefined | IssueOrPullRequestType, ): Promise { return (await this.container.azure)?.getIssueOrPullRequest(this, accessToken, repo.owner, repo.name, id, { diff --git a/src/plus/integrations/providers/bitbucket-server.ts b/src/plus/integrations/providers/bitbucket-server.ts index fc142fc9c3c4f..6d6b4f7ef1215 100644 --- a/src/plus/integrations/providers/bitbucket-server.ts +++ b/src/plus/integrations/providers/bitbucket-server.ts @@ -105,10 +105,10 @@ export class BitbucketServerIntegration extends GitHostIntegration< return Promise.resolve(undefined); } - protected override async getProviderIssueOrPullRequest( + protected override async getProviderLinkedIssueOrPullRequest( { accessToken }: AuthenticationSession, repo: BitbucketRepositoryDescriptor, - id: string, + { id }: { id: string; key: string }, type: undefined | IssueOrPullRequestType, ): Promise { if (type === 'issue') { diff --git a/src/plus/integrations/providers/bitbucket.ts b/src/plus/integrations/providers/bitbucket.ts index 809a7779acab2..cf4255968f2e3 100644 --- a/src/plus/integrations/providers/bitbucket.ts +++ b/src/plus/integrations/providers/bitbucket.ts @@ -87,10 +87,10 @@ export class BitbucketIntegration extends GitHostIntegration< return Promise.resolve(undefined); } - protected override async getProviderIssueOrPullRequest( + protected override async getProviderLinkedIssueOrPullRequest( { accessToken }: AuthenticationSession, repo: BitbucketRepositoryDescriptor, - id: string, + { id }: { id: string; key: string }, type: undefined | IssueOrPullRequestType, ): Promise { return (await this.container.bitbucket)?.getIssueOrPullRequest( diff --git a/src/plus/integrations/providers/github.ts b/src/plus/integrations/providers/github.ts index b83e9738a4597..24ba41d9e8dda 100644 --- a/src/plus/integrations/providers/github.ts +++ b/src/plus/integrations/providers/github.ts @@ -83,10 +83,10 @@ abstract class GitHubIntegrationBase extends Gi }); } - protected override async getProviderIssueOrPullRequest( + protected override async getProviderLinkedIssueOrPullRequest( { accessToken }: AuthenticationSession, repo: GitHubRepositoryDescriptor, - id: string, + { id }: { id: string; key: string }, ): Promise { return (await this.container.github)?.getIssueOrPullRequest( this, diff --git a/src/plus/integrations/providers/gitlab.ts b/src/plus/integrations/providers/gitlab.ts index ca226ef815278..bb4ff22e8bab6 100644 --- a/src/plus/integrations/providers/gitlab.ts +++ b/src/plus/integrations/providers/gitlab.ts @@ -87,10 +87,10 @@ abstract class GitLabIntegrationBase extends Gi }); } - protected override async getProviderIssueOrPullRequest( + protected override async getProviderLinkedIssueOrPullRequest( { accessToken }: AuthenticationSession, repo: GitLabRepositoryDescriptor, - id: string, + { id }: { id: string; key: string }, ): Promise { return (await this.container.gitlab)?.getIssueOrPullRequest( this, diff --git a/src/plus/integrations/providers/jira.ts b/src/plus/integrations/providers/jira.ts index b2373d05ec735..d81c3ca8f7dc8 100644 --- a/src/plus/integrations/providers/jira.ts +++ b/src/plus/integrations/providers/jira.ts @@ -272,15 +272,15 @@ export class JiraIntegration extends IssuesIntegration { const api = await this.getProvidersApi(); const issue = await api.getIssue( this.id, - { resourceId: resource.id, number: id }, + { resourceId: resource.id, number: key }, { accessToken: session.accessToken }, ); return issue != null ? toIssueShape(issue, this) : undefined; diff --git a/src/plus/integrations/providers/linear.ts b/src/plus/integrations/providers/linear.ts index 5e33f25a24a1b..a4d8559d72ec2 100644 --- a/src/plus/integrations/providers/linear.ts +++ b/src/plus/integrations/providers/linear.ts @@ -210,10 +210,10 @@ export class LinearIntegration extends IssuesIntegration { const issue = await this.getRawProviderIssue(session, resource, id);