fix: improve git remoteUrl parsing (#4147)

This commit is contained in:
Nico Domino 2024-06-24 17:53:22 +02:00 committed by GitHub
parent cf2adf4d68
commit d013b7baf7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 126 additions and 16 deletions

View File

@ -58,6 +58,7 @@
"@types/diff": "^5.2.1",
"@types/diff-match-patch": "^1.0.36",
"@types/eslint__js": "^8.42.3",
"@types/git-url-parse": "^9.0.3",
"@types/lscache": "^1.3.4",
"@types/marked": "^5.0.2",
"@typescript-eslint/parser": "^7.13.1",
@ -72,6 +73,7 @@
"eslint-plugin-import-x": "^0.5.1",
"eslint-plugin-square-svelte-store": "^1.0.0",
"eslint-plugin-svelte": "2.40.0",
"git-url-parse": "^14.0.0",
"globals": "^15.6.0",
"inter-ui": "^4.0.2",
"leven": "^4.0.0",

View File

@ -0,0 +1,42 @@
import { GitHubService } from './service';
import { BehaviorSubject } from 'rxjs';
import { expect, test, describe } from 'vitest';
const exampleRemoteUrls = [
'ssh://user@host.xz:123/org/repo.git/',
'ssh://user@host.xz/org/repo.git/',
'ssh://host.xz:123/org/repo.git/',
'ssh://host.xz:123/org/repo',
'ssh://host.xz/org/repo.git/',
'ssh://host.xz/org/repo.git',
'ssh://host.xz/org/repo',
'ssh://user@host.xz/org/repo.git/',
'ssh://user@host.xz/org/repo.git',
'ssh://user@host.xz/org/repo',
'host.xz:org/repo.git/',
'host.xz:org/repo.git',
'host.xz:org/repo',
'user@host.xz:org/repo.git/',
'user@host.xz:org/repo.git',
'user@host.xz:org/repo',
'git@github.com:org/repo.git/',
'git@github.com:org/repo.git',
'git@github.com:org/repo',
'https://github.com/org/repo.git/',
'https://github.com/org/repo.git',
'https://github.com/org/repo'
];
describe.concurrent('GitHubService', () => {
describe.concurrent('parse GitHub remote URL', () => {
test.each(exampleRemoteUrls)('%s', (remoteUrl) => {
const accessToken$ = new BehaviorSubject<string | undefined>('token');
const remoteUrl$ = new BehaviorSubject<string | undefined>(remoteUrl);
const githubService = new GitHubService(accessToken$, remoteUrl$);
expect(githubService.owner).toBe('org');
expect(githubService.repo).toBe('repo');
});
});
});

View File

@ -12,6 +12,7 @@ import { showError, showToast, type Toast } from '$lib/notifications/toasts';
import { sleep } from '$lib/utils/sleep';
import * as toasts from '$lib/utils/toasts';
import { Octokit } from '@octokit/rest';
import GitUrlParse from 'git-url-parse';
import lscache from 'lscache';
import posthog from 'posthog-js';
import {
@ -78,8 +79,8 @@ export class GitHubService {
baseUrl: 'https://api.github.com'
});
if (remoteUrl) {
const [owner, repo] = remoteUrl.split(/.git$/)[0].split(/\/|:/).slice(-2);
this._repo = repo;
const { owner, name } = GitUrlParse(remoteUrl);
this._repo = name;
this._owner = owner;
}
}),

View File

@ -1,4 +1,4 @@
import { convertRemoteToWebUrl } from '$lib/utils/url';
import { remoteUrlIsHttp, convertRemoteToWebUrl } from '$lib/utils/url';
import { describe, expect, test } from 'vitest';
describe.concurrent('cleanUrl', () => {
@ -25,4 +25,20 @@ describe.concurrent('cleanUrl', () => {
'https://github.com/user/repo'
);
});
const httpRemoteUrls = ['https://github.com/user/repo.git', 'http://192.168.1.1/user/repo.git'];
test.each(httpRemoteUrls)('HTTP Remote - %s', (remoteUrl) => {
expect(remoteUrlIsHttp(remoteUrl)).toBe(true);
});
const nonHttpRemoteUrls = [
'git@github.com:user/repo.git',
'ssh://git@github.com:22/user/repo.git',
'git://github.com/user/repo.git'
];
test.each(nonHttpRemoteUrls)('Non HTTP Remote - %s', (remoteUrl) => {
expect(remoteUrlIsHttp(remoteUrl)).toBe(false);
});
});

View File

@ -1,5 +1,6 @@
import { showToast } from '$lib/notifications/toasts';
import { open } from '@tauri-apps/api/shell';
import GitUrlParse from 'git-url-parse';
import { posthog } from 'posthog-js';
export function openExternalUrl(href: string) {
@ -25,20 +26,16 @@ export function openExternalUrl(href: string) {
// turn a git remote url into a web url (github, gitlab, bitbucket, etc)
export function convertRemoteToWebUrl(url: string): string {
if (url.startsWith('http')) {
return url.replace('.git', '').trim();
} else if (url.startsWith('ssh')) {
url = url.replace('ssh://git@', '');
const [host, ...paths] = url.split('/');
const path = paths.join('/').replace('.git', '');
const protocol = /\d+\.\d+\.\d+\.\d+/.test(host) ? 'http' : 'https';
const [hostname, _port] = host.split(':');
return `${protocol}://${hostname}/${path}`;
} else {
return url.replace(':', '/').replace('git@', 'https://').replace('.git', '').trim();
}
const gitRemote = GitUrlParse(url);
const ipv4Regex = new RegExp(/^([0-9]+(\.|$)){4}/);
const protocol = ipv4Regex.test(gitRemote.resource) ? 'http' : 'https';
return `${protocol}://${gitRemote.resource}/${gitRemote.owner}/${gitRemote.name}`;
}
export function remoteUrlIsHttp(url: string): boolean {
return url.startsWith('http');
const httpProtocols = ['http', 'https'];
const gitRemote = GitUrlParse(url);
return httpProtocols.includes(gitRemote.protocol);
}

View File

@ -114,6 +114,9 @@ importers:
'@types/eslint__js':
specifier: ^8.42.3
version: 8.42.3
'@types/git-url-parse':
specifier: ^9.0.3
version: 9.0.3
'@types/lscache':
specifier: ^1.3.4
version: 1.3.4
@ -156,6 +159,9 @@ importers:
eslint-plugin-svelte:
specifier: 2.40.0
version: 2.40.0(eslint@9.5.0)(svelte@5.0.0-next.149)
git-url-parse:
specifier: ^14.0.0
version: 14.0.0
globals:
specifier: ^15.6.0
version: 15.6.0
@ -1312,6 +1318,9 @@ packages:
'@types/express@4.17.21':
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
'@types/git-url-parse@9.0.3':
resolution: {integrity: sha512-Wrb8zeghhpKbYuqAOg203g+9YSNlrZWNZYvwxJuDF4dTmerijqpnGbI79yCuPtHSXHPEwv1pAFUB4zsSqn82Og==}
'@types/http-assert@1.5.5':
resolution: {integrity: sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==}
@ -2091,6 +2100,12 @@ packages:
get-tsconfig@4.7.5:
resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==}
git-up@7.0.0:
resolution: {integrity: sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==}
git-url-parse@14.0.0:
resolution: {integrity: sha512-NnLweV+2A4nCvn4U/m2AoYu0pPKlsmhK9cknG7IMwsjFY1S2jxM+mAhsDxyxfCIGfGaD+dozsyX4b6vkYc83yQ==}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -2318,6 +2333,9 @@ packages:
resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
engines: {node: '>= 0.4'}
is-ssh@1.4.0:
resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==}
is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
@ -2625,6 +2643,12 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
parse-path@7.0.0:
resolution: {integrity: sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==}
parse-url@8.1.0:
resolution: {integrity: sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==}
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@ -2789,6 +2813,9 @@ packages:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'}
protocols@2.0.1:
resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==}
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
@ -4621,6 +4648,8 @@ snapshots:
'@types/qs': 6.9.15
'@types/serve-static': 1.15.7
'@types/git-url-parse@9.0.3': {}
'@types/http-assert@1.5.5': {}
'@types/http-errors@2.0.4': {}
@ -5590,6 +5619,15 @@ snapshots:
dependencies:
resolve-pkg-maps: 1.0.0
git-up@7.0.0:
dependencies:
is-ssh: 1.4.0
parse-url: 8.1.0
git-url-parse@14.0.0:
dependencies:
git-up: 7.0.0
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@ -5822,6 +5860,10 @@ snapshots:
dependencies:
call-bind: 1.0.7
is-ssh@1.4.0:
dependencies:
protocols: 2.0.1
is-string@1.0.7:
dependencies:
has-tostringtag: 1.0.2
@ -6099,6 +6141,14 @@ snapshots:
dependencies:
callsites: 3.1.0
parse-path@7.0.0:
dependencies:
protocols: 2.0.1
parse-url@8.1.0:
dependencies:
parse-path: 7.0.0
path-exists@4.0.0: {}
path-is-absolute@1.0.1: {}
@ -6223,6 +6273,8 @@ snapshots:
progress@2.0.3: {}
protocols@2.0.1: {}
proxy-from-env@1.1.0: {}
punycode@2.3.0: {}