Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

## [Unreleased]

### Added

- Adds enhanced integration with Linear ([#4543](https://github.com/gitkraken/vscode-gitlens/issues/4543))

## [17.4.1] - 2025-08-26

### Fixed
Expand Down
14 changes: 7 additions & 7 deletions docs/telemetry-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ void
```typescript
{
'hostingProvider.key': string,
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'linear' | 'trello'
}
```

Expand All @@ -679,7 +679,7 @@ void
```typescript
{
'hostingProvider.key': string,
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'linear' | 'trello'
}
```

Expand All @@ -690,7 +690,7 @@ void
```typescript
{
'issueProvider.key': string,
'issueProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
'issueProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'linear' | 'trello'
}
```

Expand All @@ -701,7 +701,7 @@ void
```typescript
{
'issueProvider.key': string,
'issueProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
'issueProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'linear' | 'trello'
}
```

Expand Down Expand Up @@ -735,7 +735,7 @@ or when connection refresh is skipped due to being a non-cloud session

```typescript
{
'integration.id': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
'integration.id': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'linear' | 'trello'
}
```

Expand Down Expand Up @@ -2892,7 +2892,7 @@ void
```typescript
{
'hostingProvider.key': string,
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello',
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'linear' | 'trello',
// @deprecated: true
'remoteProviders.key': string
}
Expand All @@ -2905,7 +2905,7 @@ void
```typescript
{
'hostingProvider.key': string,
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello',
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'linear' | 'trello',
// @deprecated: true
'remoteProviders.key': string
}
Expand Down
2 changes: 1 addition & 1 deletion images/icons/provider-bitbucket.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions images/icons/provider-linear.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion images/icons/template/mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,6 @@
"repository": 61763,
"worktree": 61764,
"worktree-filled": 61765,
"repository-cloud": 61766
"repository-cloud": 61766,
"provider-linear": 61767
}
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10992,6 +10992,13 @@
"fontPath": "dist/glicons.woff2",
"fontCharacter": "\\f146"
}
},
"gitlens-provider-linear": {
"description": "provider-linear icon",
"default": {
"fontPath": "dist/glicons.woff2",
"fontCharacter": "\\f147"
}
}
},
"menus": {
Expand Down Expand Up @@ -25043,7 +25050,7 @@
},
"dependencies": {
"@gitkraken/gitkraken-components": "13.0.0-vnext.8",
"@gitkraken/provider-apis": "0.29.6",
"@gitkraken/provider-apis": "0.29.7",
"@gitkraken/shared-web-components": "0.1.1-rc.15",
"@gk-nzaytsev/fast-string-truncated-width": "1.1.0",
"@lit-labs/signals": "0.1.3",
Expand Down
53 changes: 48 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/autolinks/autolinksProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,11 @@ export class AutolinksProvider implements Disposable {
}

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;
Expand Down
6 changes: 3 additions & 3 deletions src/autolinks/utils/-webview/autolinks.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function serializeAutolink(value: Autolink): Autolink {
return serialized;
}

export const supportedAutolinkIntegrations = [IssuesCloudHostIntegrationId.Jira];
export const supportedAutolinkIntegrations = [IssuesCloudHostIntegrationId.Jira, IssuesCloudHostIntegrationId.Linear];

export function isDynamic(ref: AutolinkReference | DynamicAutolinkReference): ref is DynamicAutolinkReference {
return !('prefix' in ref) && !('url' in ref);
Expand Down Expand Up @@ -154,10 +154,10 @@ export function getBranchAutolinks(branchName: string, refsets: Readonly<RefSet[
let match;
// Sort refsets so that issue integrations are checked first for matches
const sortedRefSets = [...refsets].sort((a, b) => {
if (a[0]?.id === IssuesCloudHostIntegrationId.Jira || a[0]?.id === IssuesCloudHostIntegrationId.Trello) {
if (a[0]?.id && Object.values<string>(IssuesCloudHostIntegrationId).includes(a[0].id)) {
return -1;
}
if (b[0]?.id === IssuesCloudHostIntegrationId.Jira || b[0]?.id === IssuesCloudHostIntegrationId.Trello) {
if (b[0]?.id && Object.values<string>(IssuesCloudHostIntegrationId).includes(b[0].id)) {
return 1;
}
return 0;
Expand Down
15 changes: 14 additions & 1 deletion src/constants.integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export enum GitSelfManagedHostIntegrationId {

export enum IssuesCloudHostIntegrationId {
Jira = 'jira',
Linear = 'linear',
Trello = 'trello',
}

Expand All @@ -30,7 +31,10 @@ export type IssuesHostIntegrationIds = IssuesCloudHostIntegrationId;

export type IntegrationIds = GitHostIntegrationIds | IssuesHostIntegrationIds;

export const supportedOrderedCloudIssuesIntegrationIds = [IssuesCloudHostIntegrationId.Jira];
export const supportedOrderedCloudIssuesIntegrationIds = [
IssuesCloudHostIntegrationId.Jira,
IssuesCloudHostIntegrationId.Linear,
];
export const supportedOrderedCloudIntegrationIds = [
GitCloudHostIntegrationId.GitHub,
GitSelfManagedHostIntegrationId.CloudGitHubEnterprise,
Expand All @@ -41,6 +45,7 @@ export const supportedOrderedCloudIntegrationIds = [
GitCloudHostIntegrationId.Bitbucket,
GitSelfManagedHostIntegrationId.BitbucketServer,
IssuesCloudHostIntegrationId.Jira,
IssuesCloudHostIntegrationId.Linear,
];

export const integrationIds = [
Expand All @@ -55,6 +60,7 @@ export const integrationIds = [
GitSelfManagedHostIntegrationId.GitHubEnterprise,
GitSelfManagedHostIntegrationId.GitLabSelfHosted,
IssuesCloudHostIntegrationId.Jira,
IssuesCloudHostIntegrationId.Linear,
IssuesCloudHostIntegrationId.Trello,
];

Expand Down Expand Up @@ -142,4 +148,11 @@ export const supportedCloudIntegrationDescriptors: IntegrationDescriptor[] = [
supports: ['issues'],
requiresPro: true,
},
{
id: IssuesCloudHostIntegrationId.Linear,
name: 'Linear',
icon: 'gl-provider-linear',
supports: ['issues'],
requiresPro: true,
},
];
1 change: 0 additions & 1 deletion src/git/models/commit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,6 @@ export class GitCommit implements GitRevisionReference {
if (this.isUncommitted) return undefined;

remote ??= await this.container.git.getRepositoryService(this.repoPath).remotes.getBestRemoteWithIntegration();
if (remote?.provider == null) return undefined;

// TODO@eamodio should we cache these? Seems like we would use more memory than it's worth
// async function getCore(this: GitCommit): Promise<Map<string, EnrichedAutolink> | undefined> {
Expand Down
1 change: 1 addition & 0 deletions src/git/models/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class Issue implements IssueShape {
public readonly thumbsUpCount?: number,
public readonly body?: string,
public readonly project?: IssueProject,
public readonly number?: string,
) {}
}

Expand Down
1 change: 0 additions & 1 deletion src/hovers/hovers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ export async function detailsMessage(

const cfg = configuration.get('hovers');
const enhancedAutolinks =
remote?.provider != null &&
options?.autolinks !== false &&
(options?.autolinks || cfg.autolinks.enabled) &&
cfg.autolinks.enhanced &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ export class IntegrationAuthenticationService implements Disposable {
await import(/* webpackChunkName: "integrations" */ './jira')
).JiraAuthenticationProvider(this.container, this, this.configuredIntegrationService);
break;
case IssuesCloudHostIntegrationId.Linear:
provider = new (
await import(/* webpackChunkName: "integrations" */ './linear')
).LinearAuthenticationProvider(this.container, this, this.configuredIntegrationService);
break;
default:
provider = new BuiltInAuthenticationProvider(
this.container,
Expand Down
8 changes: 8 additions & 0 deletions src/plus/integrations/authentication/linear.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { IssuesCloudHostIntegrationId } from '../../../constants.integrations';
import { CloudIntegrationAuthenticationProvider } from './integrationAuthenticationProvider';

export class LinearAuthenticationProvider extends CloudIntegrationAuthenticationProvider<IssuesCloudHostIntegrationId.Linear> {
protected override get authProviderId(): IssuesCloudHostIntegrationId.Linear {
return IssuesCloudHostIntegrationId.Linear;
}
}
Loading
Loading