Skip to content

Commit 66b3adc

Browse files
committed
feat: add gitlab avatars
Refactor Github avatar function into a generic NoreplyAddress function with Gitlab avatar option Closes #302
1 parent 640d3f6 commit 66b3adc

File tree

4 files changed

+34
-7
lines changed

4 files changed

+34
-7
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
66

77
## [Unreleased]
88

9+
### Added
10+
- Adds GitLab Avatar support — closes [#302](https://github.com/gitkraken/vscode-gitlens/issues/302) via [#2640](https://github.com/gitkraken/vscode-gitlens/pull/2640)
11+
912
## [13.5.0] - 2023-04-07
1013

1114
### Added

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,7 @@ A big thanks to the people that have contributed to this project:
12261226
- Zyck ([@qzyse2017](https://github.com/qzyse2017)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=qzyse2017)
12271227
- Yonatan Greenfeld ([@YonatanGreenfeld](https://github.com/YonatanGreenfeld)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=YonatanGreenfeld)
12281228
- WofWca ([@WofWca](https://github.com/WofWca)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=WofWca)
1229+
- 🐇 ([@BunnyTheLifeguard](https://github.com/bunnythelifeguard)) — [contributions](https://github.com/gitkraken/vscode-gitlens/commits?author=bunnythelifeguard)
12291230

12301231
Also special thanks to the people that have provided support, testing, brainstorming, etc:
12311232

src/avatars.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { GravatarDefaultStyle } from './config';
44
import type { StoredAvatar } from './constants';
55
import { Container } from './container';
66
import { getGitHubNoReplyAddressParts } from './git/remotes/github';
7+
import { getGitLabNoReplyAddressParts } from './git/remotes/gitlab';
78
import { configuration } from './system/configuration';
89
import { getContext } from './system/context';
910
import { debounce } from './system/function';
@@ -153,7 +154,7 @@ function createOrUpdateAvatar(
153154
let avatar = avatarCache!.get(key);
154155
if (avatar == null) {
155156
avatar = {
156-
uri: email != null && email.length !== 0 ? getAvatarUriFromGitHubNoReplyAddress(email, size) : undefined,
157+
uri: email != null && email.length !== 0 ? getAvatarUriFromNoReplyAddress(email, size) : undefined,
157158
fallback: getAvatarUriFromGravatar(hash, size, defaultStyle),
158159
timestamp: 0,
159160
retries: 0,
@@ -195,13 +196,24 @@ export function getAvatarUriFromGravatarEmail(email: string, size: number, defau
195196
return getAvatarUriFromGravatar(md5(email.trim().toLowerCase()), size, defaultStyle);
196197
}
197198

198-
function getAvatarUriFromGitHubNoReplyAddress(email: string, size: number = 16): Uri | undefined {
199-
const parts = getGitHubNoReplyAddressParts(email);
200-
if (parts == null || !equalsIgnoreCase(parts.authority, 'github.com')) return undefined;
199+
function getAvatarUriFromNoReplyAddress(email: string, size: number = 16): Uri | undefined {
200+
const domain = email.split('@')[1];
201201

202-
return Uri.parse(
203-
`https://avatars.githubusercontent.com/${parts.userId ? `u/${parts.userId}` : parts.login}?size=${size}`,
204-
);
202+
if (domain === 'users.noreply.github.com') {
203+
const parts = getGitHubNoReplyAddressParts(email);
204+
if (parts == null || !equalsIgnoreCase(parts.authority, 'github.com')) return undefined;
205+
206+
return Uri.parse(
207+
`https://avatars.githubusercontent.com/${parts.userId ? `u/${parts.userId}` : parts.login}?size=${size}`,
208+
);
209+
} else if (domain === 'users.noreply.gitlab.com') {
210+
const parts = getGitLabNoReplyAddressParts(email);
211+
if (parts == null || !equalsIgnoreCase(parts.authority, 'gitlab.com')) return undefined;
212+
213+
return Uri.parse(`https://gitlab.com/uploads/-/system/user/avatar/${parts.userId}/avatar.png?width=${size}`);
214+
}
215+
216+
return undefined;
205217
}
206218

207219
async function getAvatarUriFromRemoteProvider(

src/git/remotes/gitlab.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,17 @@ export class GitLabRemote extends RichRemoteProvider {
377377
return Promise.resolve(undefined);
378378
}
379379
}
380+
const gitLabNoReplyAddressRegex = /^(?:(\d+)-)?([a-zA-Z\d-]{1,39})@users\.noreply\.(.*)$/i;
381+
382+
export function getGitLabNoReplyAddressParts(
383+
email: string,
384+
): { userId: string; login: string; authority: string } | undefined {
385+
const match = gitLabNoReplyAddressRegex.exec(email);
386+
if (match == null) return undefined;
387+
388+
const [, userId, login, authority] = match;
389+
return { userId: userId, login: login, authority: authority };
390+
}
380391

381392
export class GitLabAuthenticationProvider implements Disposable, IntegrationAuthenticationProvider {
382393
private readonly _disposable: Disposable;

0 commit comments

Comments
 (0)