From f143811efac5993f8f06c24a0484e81e56bbcbb2 Mon Sep 17 00:00:00 2001 From: Miggy Eusebio Date: Tue, 26 Sep 2023 08:45:42 -0700 Subject: [PATCH] GKCS-4072 general updates & updating comparison link generation (#12) * rm unused case * reorganize github/gitlab code * rm unnecessary fallback url * update comparison links --- src/hosts/github.ts | 389 +++++++++++++++++++------------------------- src/hosts/gitlab.ts | 245 +++++++++++----------------- 2 files changed, 257 insertions(+), 377 deletions(-) diff --git a/src/hosts/github.ts b/src/hosts/github.ts index 6e6efae..6583f22 100644 --- a/src/hosts/github.ts +++ b/src/hosts/github.ts @@ -38,41 +38,50 @@ export function injectionScope(url: string) { el.remove(); } + try { + const insertions = this.getInsertions(); + this.insertHTML(insertions); + } catch (ex) { + debugger; + console.error(ex); + } + } + + private getInsertions(): Map { const insertions = new Map(); - try { - const label = 'Open with GitKraken'; - const url = this.transformUrl('gkdev', 'open'); - - const [, , , type] = this.uri.pathname.split('/'); - switch (type) { - case 'commit': - insertions.set('.commit > #browse-at-time-link', { - html: /*html*/ `${this.getGitKrakenSvg( - 22, - undefined, - 'position:relative; top:2px;', - )}`, - position: 'afterend', - }); + const label = 'Open with GitKraken'; + const url = this.transformUrl('gkdev', 'open'); + + const [, , , type] = this.uri.pathname.split('/'); + switch (type) { + case 'commit': + insertions.set('.commit > #browse-at-time-link', { + html: /*html*/ `${this.getGitKrakenSvg( + 22, + undefined, + 'position:relative; top:2px;', + )}`, + position: 'afterend', + }); - break; - case 'compare': - insertions.set('.js-range-editor', { - html: /*html*/ `${this.getGitKrakenSvg( - 22, - undefined, - 'position:relative; top:2px;', - )}`, - position: 'afterbegin', - }); + break; + case 'compare': + insertions.set('.js-range-editor', { + html: /*html*/ `${this.getGitKrakenSvg( + 22, + undefined, + 'position:relative; top:2px;', + )}`, + position: 'afterbegin', + }); - break; - case 'pull': { - const compareUrl = this.transformUrl('gkdev', 'compare'); + break; + case 'pull': { + const compareUrl = this.transformUrl('gkdev', 'compare'); - insertions.set('[data-target="get-repo.modal"] #local-panel ul li:first-child', { - html: /*html*/ `
  • + insertions.set('[data-target="get-repo.modal"] #local-panel ul li:first-child', { + html: /*html*/ `
  • ${this.getGitKrakenSvg(16, 'mr-2')} ${label} @@ -84,84 +93,83 @@ export function injectionScope(url: string) { Open Comparison with GitKraken
  • `, - position: 'afterend', - }); + position: 'afterend', + }); - break; - } - case 'tree': - case undefined: - insertions.set('[data-target="get-repo.modal"] #local-panel ul li:first-child', { - html: /*html*/ `
  • + break; + } + case 'tree': + case undefined: + insertions.set('[data-target="get-repo.modal"] #local-panel ul li:first-child', { + html: /*html*/ `
  • ${this.getGitKrakenSvg(16, 'mr-2')} ${label}
  • `, - position: 'afterend', - }); + position: 'afterend', + }); - break; - default: { - insertions.set('.file-navigation get-repo', { - html: /*html*/ `${this.getGitKrakenSvg( - 22, - undefined, - 'position:relative; top:2px;', - )}`, - position: 'beforebegin', - }); - - insertions.set('[data-target="get-repo.modal"] #local-panel ul li:first-child', { - html: /*html*/ `
  • + break; + default: { + insertions.set('.file-navigation get-repo', { + html: /*html*/ `${this.getGitKrakenSvg( + 22, + undefined, + 'position:relative; top:2px;', + )}`, + position: 'beforebegin', + }); + + insertions.set('[data-target="get-repo.modal"] #local-panel ul li:first-child', { + html: /*html*/ `
  • ${this.getGitKrakenSvg(16, 'mr-2')} ${label}
  • `, - position: 'afterend', - }); + position: 'afterend', + }); - break; - } + break; } + } + return insertions; + } - if (insertions.size) { - for (const [selector, { html, position }] of insertions) { - const el = document.querySelector(selector); - if (el) { - insertions.delete(selector); - el.insertAdjacentHTML(position, html); - } + private insertHTML(insertions: Map) { + if (insertions.size) { + for (const [selector, { html, position }] of insertions) { + const el = document.querySelector(selector); + if (el) { + insertions.delete(selector); + el.insertAdjacentHTML(position, html); } + } - if (!insertions.size) return; + if (!insertions.size) return; - this._observer = new MutationObserver(() => { - if (this._timer != null) { - clearTimeout(this._timer); - } + this._observer = new MutationObserver(() => { + if (this._timer != null) { + clearTimeout(this._timer); + } - this._timer = setTimeout(() => { - for (const [selector, { html, position }] of insertions) { - const el = document.querySelector(selector); - if (el) { - insertions.delete(selector); - el.insertAdjacentHTML(position, html); - } + this._timer = setTimeout(() => { + for (const [selector, { html, position }] of insertions) { + const el = document.querySelector(selector); + if (el) { + insertions.delete(selector); + el.insertAdjacentHTML(position, html); } + } - if (!insertions.size) { - this._observer?.disconnect(); - this._observer = undefined; - } - }, 100); - }); - this._observer.observe(document.body, { childList: true, subtree: true }); - } - } catch (ex) { - debugger; - console.error(ex); + if (!insertions.size) { + this._observer?.disconnect(); + this._observer = undefined; + } + }, 100); + }); + this._observer.observe(document.body, { childList: true, subtree: true }); } } @@ -186,152 +194,87 @@ export function injectionScope(url: string) { const repoId = '-'; - let url = new URL(MODE === 'production' ? 'https://gitkraken.dev' : 'https://dev.gitkraken.dev'); - switch (target) { - case 'gitkraken': { - switch (type) { - case 'commit': - url = new URL(`${target}://repolink/${repoId}/commit/${rest.join('/')}`); - break; - case 'pull': { - const [prNumber] = rest; - - const headTreeUrl = - document.querySelector('.commit-ref.head-ref a')?.href; - if (!headTreeUrl) { - url = new URL(`${target}://repolink/${repoId}`); - url.searchParams.set('pr', prNumber); - url.searchParams.set('prUrl', this.uri.toString()); - } else { - const [, prOwner, prRepo, , ...prBranch] = new URL(headTreeUrl).pathname.split('/'); - url = new URL(`${target}://repolink/${repoId}/branch/${prBranch.join('/')}`); - url.searchParams.set('pr', prNumber); - url.searchParams.set('prUrl', this.uri.toString()); - - if (prOwner !== owner || prRepo !== repo) { - const prRepoUrl = new URL(this.uri.toString()); - prRepoUrl.hash = ''; - prRepoUrl.search = ''; - prRepoUrl.pathname = `/${owner}/${repo}.git`; - url.searchParams.set('prRepoUrl', prRepoUrl.toString()); - - owner = prOwner; - repo = prRepo; - } - } - break; - } - case 'tree': { - // TODO@eamodio this is naive as it assumes everything after the tree is the branch or commit, but it could also contain a path - const prButtonForBranchPage = document.querySelector( - '.btn-link.no-underline.color-fg-muted', - ); - if (prButtonForBranchPage && prButtonForBranchPage.textContent?.includes('Contribute')) { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/b/${rest.join('/')}`); - } else { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); - } - break; - } - default: - url = new URL(`${target}://repolink/${repoId}`); - break; + let url; + switch (type) { + case 'commit': + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); + break; + case 'compare': { + let comparisonTarget = rest.join('/'); + if (!comparisonTarget) { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); + break; + } + const sameOrigin = !comparisonTarget.includes(':'); + if (sameOrigin) { + const branches = comparisonTarget.split('...').map(branch => `${owner}/${repo}:${branch}`); + comparisonTarget = branches.join('...'); } + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/compare/${comparisonTarget}`); break; } - case 'vscode': - case 'vscode-insiders': { - switch (type) { - case 'commit': - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); - break; - case 'compare': { - let comparisonTarget = rest.join('/'); - if (!comparisonTarget) { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); - break; + case 'pull': { + const [prNumber] = rest; + + const headTreeUrl = document.querySelector('.commit-ref.head-ref a')?.href; + if (headTreeUrl) { + const [, prOwner, prRepo, , ...prBranch] = new URL(headTreeUrl).pathname.split('/'); + + if (action === 'compare') { + const baseTreeUrl = + document.querySelector('.commit-ref.base-ref a')?.href; + if (baseTreeUrl) { + const [, baseOwner, baseRepo, , ...baseBranch] = new URL(baseTreeUrl).pathname.split( + '/', + ); + + const baseBranchString = `${baseOwner}/${baseRepo}:${baseBranch.join('/')}`; + const prBranchString = `${prOwner}/${prRepo}:${prBranch.join('/')}`; + + url = new URL( + `${target}://eamodio.gitlens/link/r/${repoId}/compare/${baseBranchString}...${prBranchString}`, + ); } - const sameOrigin = !comparisonTarget.includes(':'); - if (sameOrigin) { - const branches = comparisonTarget.split('...').map(branch => `origin/${branch}`); - comparisonTarget = branches.join('...'); - } - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/compare/${comparisonTarget}`); - break; } - case 'pull': { - const [prNumber] = rest; - - const headTreeUrl = - document.querySelector('.commit-ref.head-ref a')?.href; - if (headTreeUrl) { - const [, prOwner, prRepo, , ...prBranch] = new URL(headTreeUrl).pathname.split('/'); - - if (action === 'compare') { - const baseTreeUrl = - document.querySelector('.commit-ref.base-ref a')?.href; - if (baseTreeUrl) { - const [, baseOwner, baseRepo, , ...baseBranch] = new URL( - baseTreeUrl, - ).pathname.split('/'); - - let baseBranchString = baseBranch.join('/'); - let prBranchString = prBranch.join('/'); - - if (prOwner === baseOwner && prRepo === baseRepo) { - baseBranchString = `origin/${baseBranchString}`; - prBranchString = `origin/${prBranchString}`; - } - - url = new URL( - `${target}://eamodio.gitlens/link/r/${repoId}/compare/${baseBranchString}...${prBranchString}`, - ); - } - } - - if (url == null) { - url = new URL( - `${target}://eamodio.gitlens/link/r/${repoId}/b/${prBranch.join('/')}`, - ); - } - - url.searchParams.set('pr', prNumber); - url.searchParams.set('prUrl', this.uri.toString()); - - if (prOwner !== owner || prRepo !== repo) { - const prRepoUrl = new URL(this.uri.toString()); - prRepoUrl.hash = ''; - prRepoUrl.search = ''; - prRepoUrl.pathname = `/${owner}/${repo}.git`; - url.searchParams.set('prRepoUrl', prRepoUrl.toString()); - - owner = prOwner; - repo = prRepo; - } - } else { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); - url.searchParams.set('pr', prNumber); - url.searchParams.set('prUrl', this.uri.toString()); - } - break; + + if (url == null) { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/b/${prBranch.join('/')}`); } - case 'tree': { - // TODO@miggy-e this is a pretty naive check, please update if you find a better way - // this is currently broken when branches have 40 characters or if you use the short sha of a commit - if (rest.length === 1 && rest[0].length === 40) { - // commit sha's are 40 characters long - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); - } else { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/b/${rest.join('/')}`); - } - break; + + url.searchParams.set('pr', prNumber); + url.searchParams.set('prUrl', this.uri.toString()); + + if (prOwner !== owner || prRepo !== repo) { + const prRepoUrl = new URL(this.uri.toString()); + prRepoUrl.hash = ''; + prRepoUrl.search = ''; + prRepoUrl.pathname = `/${owner}/${repo}.git`; + url.searchParams.set('prRepoUrl', prRepoUrl.toString()); + + owner = prOwner; + repo = prRepo; } - default: - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); - break; + } else { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); + url.searchParams.set('pr', prNumber); + url.searchParams.set('prUrl', this.uri.toString()); } break; } + case 'tree': { + // TODO@miggy-e this is a pretty naive check, please update if you find a better way + // this is currently broken when branches have 40 characters or if you use the short sha of a commit + if (rest.length === 1 && rest[0].length === 40) { + // commit sha's are 40 characters long + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); + } else { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/b/${rest.join('/')}`); + } + break; + } + default: + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); + break; } const remoteUrl = new URL(this.uri.toString()); diff --git a/src/hosts/gitlab.ts b/src/hosts/gitlab.ts index fd9bc37..2037081 100644 --- a/src/hosts/gitlab.ts +++ b/src/hosts/gitlab.ts @@ -14,6 +14,11 @@ export function injectionScope(url: string) { } private render() { + const insertions = this.getInsertions(); + this.insertHTML(insertions); + } + + private getInsertions(): Map { const insertions = new Map(); try { @@ -117,7 +122,10 @@ export function injectionScope(url: string) { debugger; console.error(ex); } + return insertions; + } + private insertHTML(insertions: Map) { if (insertions.size) { for (const [selector, { html, position }] of insertions) { const el = document.querySelector(selector); @@ -206,172 +214,101 @@ export function injectionScope(url: string) { const repoId = '-'; - let url = new URL(MODE === 'production' ? 'https://gitkraken.dev' : 'https://dev.gitkraken.dev'); - switch (target) { - case 'gitkraken': { - switch (type) { - case 'commit': { - url = new URL(`${target}://repolink/${repoId}/commit/${rest.join('/')}`); - break; - } - case 'merge_requests': { - const [prNumber] = rest; - - const headTreeUrl = document.querySelector( - '.merge-request-details .detail-page-description a.gl-font-monospace:nth-of-type(2)', - )?.href; - if (!headTreeUrl) { - url = new URL(`${target}://repolink/${repoId}`); - url.searchParams.set('pr', prNumber); - url.searchParams.set('prUrl', this.uri.toString()); - } else { - const { - owner: prOwner, - repo: prRepo, - rest: prBranch, - } = this.parseUrl(new URL(headTreeUrl).pathname); - - url = new URL(`${target}://repolink/${repoId}/branch/${prBranch.join('/')}`); - url.searchParams.set('pr', prNumber); - url.searchParams.set('prUrl', this.uri.toString()); - - if (prOwner !== owner || prRepo !== repo) { - const prRepoUrl = new URL(this.uri.toString()); - prRepoUrl.hash = ''; - prRepoUrl.search = ''; - prRepoUrl.pathname = `/${owner}/${repo}.git`; - url.searchParams.set('prRepoUrl', prRepoUrl.toString()); - - owner = prOwner; - repo = prRepo; - } - } - break; - } - case 'tree': { - // TODO sometimes a sha can be passed into this, which the `branch` deeplink path doesn't work with. i don't - // know how we could fix this unless we modify the deeplink spec, since differentiating a sha from a branch - // and selecting the correct deeplink route to use (/branch/... for branches, /c/... for commits) is an - // unsolveable problem. yes, full length shas are pretty easy to differentiate from branch names, but GitLab - // supports shortened shas which screws up everything - // the below line would be a good check, but isn't loaded with the initial page load, so we can't use it - // document.querySelector('[title="Copy commit SHA"]')?.getAttribute('data-clipboard-text') === rest.join('/') - url = new URL(`${target}://repolink/${repoId}/branch/${rest.join('/')}`); - break; - } - default: { - url = new URL(`${target}://repolink/${repoId}`); - break; - } + let url; + switch (type) { + case 'commit': { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); + break; + } + case 'compare': { + // get the comparison target if not already provided + let comparisonTarget = rest.join('/'); + if (!comparisonTarget) { + // TODO get the current state of the comparison pickers + // currently defaulting to a link to the repo + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); + break; + } + const sameOrigin = !comparisonTarget.includes(':'); + if (sameOrigin) { + const branches = comparisonTarget.split('...').map(branch => `${owner}/${repo}:${branch}`); + comparisonTarget = branches.join('...'); } + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/compare/${comparisonTarget}`); break; } - case 'vscode': - case 'vscode-insiders': { - switch (type) { - case 'commit': { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); - break; - } - case 'compare': { - // get the comparison target if not already provided - let comparisonTarget = rest.join('/'); - if (!comparisonTarget) { - // TODO get the current state of the comparison pickers - // currently defaulting to a link to the repo - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); - break; - } - const sameOrigin = !comparisonTarget.includes(':'); - if (sameOrigin) { - const branches = comparisonTarget.split('...').map(branch => `origin/${branch}`); - comparisonTarget = branches.join('...'); - } - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/compare/${comparisonTarget}`); - break; - } - case 'merge_requests': { - const [prNumber] = rest; - - const headTreeUrl = document.querySelector( - '.merge-request-details .detail-page-description a.gl-font-monospace:nth-of-type(2)', + case 'merge_requests': { + const [prNumber] = rest; + + const headTreeUrl = document.querySelector( + '.merge-request-details .detail-page-description a.gl-font-monospace:nth-of-type(2)', + )?.href; + if (headTreeUrl) { + const { + owner: prOwner, + repo: prRepo, + rest: prBranch, + } = this.parseUrl(new URL(headTreeUrl).pathname); + + if (action === 'compare') { + const baseTreeUrl = document.querySelector( + '.merge-request-details .detail-page-description a.gl-font-monospace:nth-of-type(3)', )?.href; - if (headTreeUrl) { + if (baseTreeUrl) { const { - owner: prOwner, - repo: prRepo, - rest: prBranch, - } = this.parseUrl(new URL(headTreeUrl).pathname); - - if (action === 'compare') { - const baseTreeUrl = document.querySelector( - '.merge-request-details .detail-page-description a.gl-font-monospace:nth-of-type(3)', - )?.href; - if (baseTreeUrl) { - const { - owner: baseOwner, - repo: baseRepo, - rest: baseBranch, - } = this.parseUrl(new URL(baseTreeUrl).pathname); - - let baseBranchString = baseBranch.join('/'); - let prBranchString = prBranch.join('/'); - - if (prOwner === baseOwner && prRepo === baseRepo) { - baseBranchString = `origin/${baseBranchString}`; - prBranchString = `origin/${prBranchString}`; - } - - url = new URL( - `${target}://eamodio.gitlens/link/r/${repoId}/compare/${baseBranchString}...${prBranchString}`, - ); - } - } - - if (url == null) { - url = new URL( - `${target}://eamodio.gitlens/link/r/${repoId}/b/${prBranch.join('/')}`, - ); - } - - url.searchParams.set('pr', prNumber); - url.searchParams.set('prUrl', this.uri.toString()); - - if (prOwner !== owner || prRepo !== repo) { - const prRepoUrl = new URL(this.uri.toString()); - prRepoUrl.hash = ''; - prRepoUrl.search = ''; - prRepoUrl.pathname = `/${owner}/${repo}.git`; - url.searchParams.set('prRepoUrl', prRepoUrl.toString()); - - owner = prOwner; - repo = prRepo; - } - } else { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); - url.searchParams.set('pr', prNumber); - url.searchParams.set('prUrl', this.uri.toString()); + owner: baseOwner, + repo: baseRepo, + rest: baseBranch, + } = this.parseUrl(new URL(baseTreeUrl).pathname); + + const baseBranchString = `${baseOwner}/${baseRepo}:${baseBranch.join('/')}`; + const prBranchString = `${prOwner}/${prRepo}:${prBranch.join('/')}`; + + url = new URL( + `${target}://eamodio.gitlens/link/r/${repoId}/compare/${baseBranchString}...${prBranchString}`, + ); } - break; } - case 'tree': { - // TODO@miggy-e this is a pretty naive check, please update if you find a better way - // this is currently broken when branches have 40 characters or if you use the short sha of a commit - if (rest.length === 1 && rest[0].length === 40) { - // commit sha's are 40 characters long - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); - } else { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/b/${rest.join('/')}`); - } - break; + + if (url == null) { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/b/${prBranch.join('/')}`); } - default: { - url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); - break; + + url.searchParams.set('pr', prNumber); + url.searchParams.set('prUrl', this.uri.toString()); + + if (prOwner !== owner || prRepo !== repo) { + const prRepoUrl = new URL(this.uri.toString()); + prRepoUrl.hash = ''; + prRepoUrl.search = ''; + prRepoUrl.pathname = `/${owner}/${repo}.git`; + url.searchParams.set('prRepoUrl', prRepoUrl.toString()); + + owner = prOwner; + repo = prRepo; } + } else { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); + url.searchParams.set('pr', prNumber); + url.searchParams.set('prUrl', this.uri.toString()); } break; } + case 'tree': { + // TODO@miggy-e this is a pretty naive check, please update if you find a better way + // this is currently broken when branches have 40 characters or if you use the short sha of a commit + if (rest.length === 1 && rest[0].length === 40) { + // commit sha's are 40 characters long + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/c/${rest.join('/')}`); + } else { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}/b/${rest.join('/')}`); + } + break; + } + default: { + url = new URL(`${target}://eamodio.gitlens/link/r/${repoId}`); + break; + } } const remoteUrl = new URL(this.uri.toString());