From 512d7930bc8a365401bd64f3f7dc88bbfe975221 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 28 Apr 2019 10:37:48 +0530 Subject: [PATCH 01/54] Adding compare link separately. --- source/content.ts | 1 + .../what-changed-since-previous-release.tsx | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 source/features/what-changed-since-previous-release.tsx diff --git a/source/content.ts b/source/content.ts index 3f2519b1cbd..31ff0fe4ec2 100644 --- a/source/content.ts +++ b/source/content.ts @@ -97,6 +97,7 @@ import './features/raw-file-link'; import './features/tags-dropdown'; import './features/filter-pr-by-build-status'; import './features/edit-files-faster'; +import './features/what-changed-since-previous-release'; import './features/scrollable-code-and-blockquote.css'; import './features/center-reactions-popup.css'; diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx new file mode 100644 index 00000000000..b10c7211df5 --- /dev/null +++ b/source/features/what-changed-since-previous-release.tsx @@ -0,0 +1,86 @@ +import React from 'dom-chef'; +import select from 'select-dom'; +import features from '../libs/features'; +import fetchDom from '../libs/fetch-dom'; +import {getOwnerAndRepo, getRepoPath} from '../libs/utils'; +import { diff } from '../libs/icons'; + +async function init(): Promise { + if (select.exists('.blankslate')) { + return false; + } + + const {ownerName, repoName} = getOwnerAndRepo(); + + // To extract the tag name from links like "/facebook/react/releases/tag/v16.8.6" + const tagAnchorRegExp = new RegExp(`\/${ownerName}\/${repoName}\/releases\/tag\/(.*)`); + + // To select all links like "/facebook/react/releases/tag" + const tagSelector = `*:not(li) > a[href^="/${ownerName}/${repoName}/releases/tag"]`; + + const allTagsAnchor = [...select.all(tagSelector)]; + const lastTagAnchor = allTagsAnchor[allTagsAnchor.length - 1]; + + for (let i = 0; i < allTagsAnchor.length - 1; i++) { + const diffAnchor = allTagsAnchor[i].cloneNode() as HTMLAnchorElement + diffAnchor.pathname = `/${ownerName}/${repoName}/compare/${extractTagName(allTagsAnchor[i + 1].pathname, tagAnchorRegExp)}...${extractTagName(allTagsAnchor[i].pathname, tagAnchorRegExp)}`; + + appendDiffIcon(diffAnchor, i); + } + + const nextPageLink = select('.pagination a:last-child'); + + if (!nextPageLink) { + return; + } + + const firstTagAnchorOfNextPage = await fetchDom(nextPageLink.href, tagSelector) as HTMLAnchorElement; + + lastTagAnchor.pathname = `/${ownerName}/${repoName}/compare/${extractTagName(firstTagAnchorOfNextPage.pathname, tagAnchorRegExp)}...${extractTagName(lastTagAnchor.pathname, tagAnchorRegExp)}`; +} + +const compare = () =>
Compare
+ +const appendDiffIcon = (anchorTag: HTMLAnchorElement, index: number): void => { + anchorTag.append(diff()); + anchorTag.append(compare()) + anchorTag.classList.add('muted-link'); + + if (isReleaseListPage() || isSingleTagPage()) { + select( + '.release > div:first-child > ul', + select(`.repository-content > .position-relative > .release-entry:nth-child(${index + 1}) > .release`)! + )!.append(anchorTag); + } + + if (isTagsListPage()) { + select('.commit > ul')!.append(anchorTag); + } +} + +const isReleaseListPage = (): boolean => { + return /^(releases)/.test(getRepoPath()!); +} + +const isTagsListPage = (): boolean => { + return /^(tags)/.test(getRepoPath()!); +} + +const isSingleTagPage = (): boolean => { + return /^(releases\/tag\/)/.test(getRepoPath()!); +} + +const extractTagName = (tagPathname: string, regex: RegExp): string => { + const [, tag] = tagPathname.match(regex)!; + + return tag; +}; + +features.add({ + id: 'what-changed-since-previous-release', + include: [ + features.isReleasesOrTags + ], + load: features.onAjaxedPages, + init +}); From e38619ab55228937b8a5c42d21c965862eac68e7 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 28 Apr 2019 11:33:49 +0530 Subject: [PATCH 02/54] Basic version of what-changes-since-previous-release ready 1. Edge cases not yet handled. 2. Currently only fetches the next release from the sequence and adds the compare link. 3. For the last tag on any page, uses fetchDom to retrieve the next page and extracts the tag from it. --- source/content.ts | 1 + .../what-changed-since-previous-release.css | 8 ++++ .../what-changed-since-previous-release.tsx | 44 +++++-------------- 3 files changed, 21 insertions(+), 32 deletions(-) create mode 100644 source/features/what-changed-since-previous-release.css diff --git a/source/content.ts b/source/content.ts index 31ff0fe4ec2..53896f2f257 100644 --- a/source/content.ts +++ b/source/content.ts @@ -113,6 +113,7 @@ import './features/hide-tips.css'; import './features/hide-readme-header.css'; import './features/hide-obvious-tooltips.css'; import './features/clean-discussions.css'; +import './features/what-changed-since-previous-release.css'; // Add global for easier debugging (window as any).select = select; diff --git a/source/features/what-changed-since-previous-release.css b/source/features/what-changed-since-previous-release.css new file mode 100644 index 00000000000..faf7be01c1c --- /dev/null +++ b/source/features/what-changed-since-previous-release.css @@ -0,0 +1,8 @@ +.release-entry .hidden-text-expander, +.commit .hidden-text-expander { + display: none !important; +} + +.rgh-what-changed { + margin-left: 5px; +} diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index b10c7211df5..3ef11232ab6 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -2,8 +2,7 @@ import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; -import {getOwnerAndRepo, getRepoPath} from '../libs/utils'; -import { diff } from '../libs/icons'; +import {getOwnerAndRepo} from '../libs/utils'; async function init(): Promise { if (select.exists('.blankslate')) { @@ -25,7 +24,7 @@ async function init(): Promise { const diffAnchor = allTagsAnchor[i].cloneNode() as HTMLAnchorElement diffAnchor.pathname = `/${ownerName}/${repoName}/compare/${extractTagName(allTagsAnchor[i + 1].pathname, tagAnchorRegExp)}...${extractTagName(allTagsAnchor[i].pathname, tagAnchorRegExp)}`; - appendDiffIcon(diffAnchor, i); + appendCompareIcon(allTagsAnchor[i], diffAnchor); } const nextPageLink = select('.pagination a:last-child'); @@ -36,38 +35,19 @@ async function init(): Promise { const firstTagAnchorOfNextPage = await fetchDom(nextPageLink.href, tagSelector) as HTMLAnchorElement; - lastTagAnchor.pathname = `/${ownerName}/${repoName}/compare/${extractTagName(firstTagAnchorOfNextPage.pathname, tagAnchorRegExp)}...${extractTagName(lastTagAnchor.pathname, tagAnchorRegExp)}`; -} - -const compare = () =>
Compare
- -const appendDiffIcon = (anchorTag: HTMLAnchorElement, index: number): void => { - anchorTag.append(diff()); - anchorTag.append(compare()) - anchorTag.classList.add('muted-link'); - - if (isReleaseListPage() || isSingleTagPage()) { - select( - '.release > div:first-child > ul', - select(`.repository-content > .position-relative > .release-entry:nth-child(${index + 1}) > .release`)! - )!.append(anchorTag); - } - - if (isTagsListPage()) { - select('.commit > ul')!.append(anchorTag); - } -} - -const isReleaseListPage = (): boolean => { - return /^(releases)/.test(getRepoPath()!); -} + const diffAnchor = lastTagAnchor.cloneNode() as HTMLAnchorElement + diffAnchor.pathname = `/${ownerName}/${repoName}/compare/${extractTagName(firstTagAnchorOfNextPage.pathname, tagAnchorRegExp)}...${extractTagName(lastTagAnchor.pathname, tagAnchorRegExp)}`; -const isTagsListPage = (): boolean => { - return /^(tags)/.test(getRepoPath()!); + appendCompareIcon(lastTagAnchor, diffAnchor); } -const isSingleTagPage = (): boolean => { - return /^(releases\/tag\/)/.test(getRepoPath()!); +const appendCompareIcon = (anchor: HTMLAnchorElement, compareAnchor: HTMLAnchorElement) => { + compareAnchor.append() + anchor.after( + + {compareAnchor} + + ) } const extractTagName = (tagPathname: string, regex: RegExp): string => { From 6b9e084eb848f00a2253d58e814d3266932e398c Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 28 Apr 2019 12:45:02 +0530 Subject: [PATCH 03/54] More specific selectors to avoid false matches --- .../what-changed-since-previous-release.tsx | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 3ef11232ab6..90fea9d002a 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -2,7 +2,7 @@ import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; -import {getOwnerAndRepo} from '../libs/utils'; +import {getOwnerAndRepo, getRepoPath} from '../libs/utils'; async function init(): Promise { if (select.exists('.blankslate')) { @@ -14,8 +14,7 @@ async function init(): Promise { // To extract the tag name from links like "/facebook/react/releases/tag/v16.8.6" const tagAnchorRegExp = new RegExp(`\/${ownerName}\/${repoName}\/releases\/tag\/(.*)`); - // To select all links like "/facebook/react/releases/tag" - const tagSelector = `*:not(li) > a[href^="/${ownerName}/${repoName}/releases/tag"]`; + const tagSelector = getTagSelector(ownerName, repoName); const allTagsAnchor = [...select.all(tagSelector)]; const lastTagAnchor = allTagsAnchor[allTagsAnchor.length - 1]; @@ -41,6 +40,29 @@ async function init(): Promise { appendCompareIcon(lastTagAnchor, diffAnchor); } +// To select all links like "/facebook/react/releases/tag" +const getTagSelector = (ownerName: string, repoName: string): string => { + const tagAnchorSelector = `a[href^="/${ownerName}/${repoName}/releases/tag"]`; + + if (isReleasesListPage()) { + return `.release-main-section h4.commit-title ${tagAnchorSelector}, .release-main-section .release-header ${tagAnchorSelector}`; + } + + if (isTagsListPage()) { + return `h4.commit-title > ${tagAnchorSelector}`; + } + + return tagAnchorSelector; +} + +const isReleasesListPage = () => { + return /^(releases)/.test(getRepoPath()!); +} + +const isTagsListPage = () => { + return /^(tags)/.test(getRepoPath()!); +} + const appendCompareIcon = (anchor: HTMLAnchorElement, compareAnchor: HTMLAnchorElement) => { compareAnchor.append() anchor.after( From 4d29ac84593ca1974d08697709d9aa31b6319ad0 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 00:39:13 +0530 Subject: [PATCH 04/54] Handling different tags on same commit in a single page Now, If there are multiple tags on the same commit, we traverse all the commits present on the single page and select the next commit on which different tag is present. Still not handling the case of namespaced tags. --- .../what-changed-since-previous-release.tsx | 76 +++++++++++++++---- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 90fea9d002a..4f35479225e 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -11,19 +11,25 @@ async function init(): Promise { const {ownerName, repoName} = getOwnerAndRepo(); - // To extract the tag name from links like "/facebook/react/releases/tag/v16.8.6" - const tagAnchorRegExp = new RegExp(`\/${ownerName}\/${repoName}\/releases\/tag\/(.*)`); + // To extract the tag "v16.8.6" from links like "/facebook/react/releases/tag/v16.8.6" + const tagRegExp = new RegExp(`\/${ownerName}\/${repoName}\/releases\/tag\/(.*)`); + + // To extract the commit hash from links ike "/facebook/react/commits/92a1d8feac32d03ab5ea6ac13ae4941f6ae93b54" + const commitRegExp = new RegExp(`\/${ownerName}\/${repoName}\/commit\/([0-9a-f]{5,40})`); const tagSelector = getTagSelector(ownerName, repoName); + const commitIdSelector = getCommitIdSelector(ownerName, repoName); const allTagsAnchor = [...select.all(tagSelector)]; - const lastTagAnchor = allTagsAnchor[allTagsAnchor.length - 1]; + const allTags = extractTagNames(allTagsAnchor, tagRegExp); + const allCommitIds = extractCommitIds([...select.all(commitIdSelector)], commitRegExp); - for (let i = 0; i < allTagsAnchor.length - 1; i++) { - const diffAnchor = allTagsAnchor[i].cloneNode() as HTMLAnchorElement - diffAnchor.pathname = `/${ownerName}/${repoName}/compare/${extractTagName(allTagsAnchor[i + 1].pathname, tagAnchorRegExp)}...${extractTagName(allTagsAnchor[i].pathname, tagAnchorRegExp)}`; + for (let i = 0; i < allTags.length - 1; i++) { + const previousCommitIndex = getPreviousTagCommitIndex(i, allCommitIds); - appendCompareIcon(allTagsAnchor[i], diffAnchor); + if (previousCommitIndex !== -1) { + appendCompareIcon(allTagsAnchor[i], allTags[previousCommitIndex], allTags[i]); + } } const nextPageLink = select('.pagination a:last-child'); @@ -34,10 +40,51 @@ async function init(): Promise { const firstTagAnchorOfNextPage = await fetchDom(nextPageLink.href, tagSelector) as HTMLAnchorElement; - const diffAnchor = lastTagAnchor.cloneNode() as HTMLAnchorElement - diffAnchor.pathname = `/${ownerName}/${repoName}/compare/${extractTagName(firstTagAnchorOfNextPage.pathname, tagAnchorRegExp)}...${extractTagName(lastTagAnchor.pathname, tagAnchorRegExp)}`; + appendCompareIcon( + allTagsAnchor[allTagsAnchor.length - 1], + extractTagName(firstTagAnchorOfNextPage.pathname, tagRegExp), + allTags[allTags.length - 1] + ); +} + +const getPreviousTagCommitIndex = (currentIndex: number, allCommitIds: string[]) => { + for (let i = currentIndex + 1; i < allCommitIds.length - 1; i++) { + if (allCommitIds[i] !== allCommitIds[currentIndex]) { + return i; + } + } + + return -1; +}; - appendCompareIcon(lastTagAnchor, diffAnchor); +const extractCommitIds = (allCommitIdsAnchor: HTMLAnchorElement[], commitRegExp: RegExp): string[] => { + return allCommitIdsAnchor.map((commitIdAnchor: HTMLAnchorElement): string => { + const [, commitId] = commitIdAnchor.pathname.match(commitRegExp)!; + + return commitId; + }); +} + +const extractTagNames = (allTagsAnchor: HTMLAnchorElement[], tagRegExp: RegExp): string[] => { + return allTagsAnchor.map((tagAnchor: HTMLAnchorElement): string => { + const [, tagName] = tagAnchor.pathname.match(tagRegExp)!; + + return tagName; + }); +} + +const getCommitIdSelector = (ownerName: string, repoName: string): string => { + const commitAnchorSelector = `a[href^="/${ownerName}/${repoName}/commit/"]`; + + if (isReleasesListPage()) { + return `.release-entry .release-main-section .commit > ul ${commitAnchorSelector}, .release-entry > .release > div:first-child > ul ${commitAnchorSelector}`; + } + + if (isTagsListPage()) { + return `.commit > ul ${commitAnchorSelector}`; + } + + return commitAnchorSelector; } // To select all links like "/facebook/react/releases/tag" @@ -63,11 +110,14 @@ const isTagsListPage = () => { return /^(tags)/.test(getRepoPath()!); } -const appendCompareIcon = (anchor: HTMLAnchorElement, compareAnchor: HTMLAnchorElement) => { - compareAnchor.append() +const appendCompareIcon = (anchor: HTMLAnchorElement, prevTag: string, nextTag: string): void => { + const {ownerName, repoName} = getOwnerAndRepo(); + anchor.after( - {compareAnchor} + + + ) } From 2063218075e78dcbbdaf0991ee67dc148a9d6629 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 01:42:35 +0530 Subject: [PATCH 05/54] Removed unnecessary methods and reorganized a bit --- .../what-changed-since-previous-release.tsx | 91 +++++++++---------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 4f35479225e..41f864e5a88 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -14,21 +14,19 @@ async function init(): Promise { // To extract the tag "v16.8.6" from links like "/facebook/react/releases/tag/v16.8.6" const tagRegExp = new RegExp(`\/${ownerName}\/${repoName}\/releases\/tag\/(.*)`); - // To extract the commit hash from links ike "/facebook/react/commits/92a1d8feac32d03ab5ea6ac13ae4941f6ae93b54" + // To extract the commit hash from links like "/facebook/react/commit/92a1d8feac32d03ab5ea6ac13ae4941f6ae93b54" const commitRegExp = new RegExp(`\/${ownerName}\/${repoName}\/commit\/([0-9a-f]{5,40})`); - const tagSelector = getTagSelector(ownerName, repoName); - const commitIdSelector = getCommitIdSelector(ownerName, repoName); + const allTagsAnchor = [...select.all(getTagSelector())]; + const allTags = extractAnchorValues(allTagsAnchor, tagRegExp); - const allTagsAnchor = [...select.all(tagSelector)]; - const allTags = extractTagNames(allTagsAnchor, tagRegExp); - const allCommitIds = extractCommitIds([...select.all(commitIdSelector)], commitRegExp); + const allCommitIds = extractAnchorValues([...select.all(getCommitIdSelector())], commitRegExp); - for (let i = 0; i < allTags.length - 1; i++) { - const previousCommitIndex = getPreviousTagCommitIndex(i, allCommitIds); + for (let index = 0; index < allTags.length - 1; index++) { + const previousCommitIndex = getPreviousTagCommitIndex(index + 1, allCommitIds[index], allCommitIds); if (previousCommitIndex !== -1) { - appendCompareIcon(allTagsAnchor[i], allTags[previousCommitIndex], allTags[i]); + allTagsAnchor[index].after(getCompareIcon(allTags[previousCommitIndex], allTags[index])); } } @@ -38,42 +36,45 @@ async function init(): Promise { return; } - const firstTagAnchorOfNextPage = await fetchDom(nextPageLink.href, tagSelector) as HTMLAnchorElement; + const nextPage = await fetchDom(nextPageLink.href); - appendCompareIcon( - allTagsAnchor[allTagsAnchor.length - 1], - extractTagName(firstTagAnchorOfNextPage.pathname, tagRegExp), - allTags[allTags.length - 1] - ); -} + const nextPageAllTagsAnchor = [...select.all(getTagSelector(), nextPage)]; + const nextPageAllTags = extractAnchorValues(nextPageAllTagsAnchor, tagRegExp); -const getPreviousTagCommitIndex = (currentIndex: number, allCommitIds: string[]) => { - for (let i = currentIndex + 1; i < allCommitIds.length - 1; i++) { - if (allCommitIds[i] !== allCommitIds[currentIndex]) { - return i; + const nextPageAllCommitIds = extractAnchorValues([...select.all(getCommitIdSelector())], commitRegExp); + + for (let index = 0; index < nextPageAllTags.length; index++) { + const previousCommitIndex = getPreviousTagCommitIndex(index, allCommitIds[allCommitIds.length - 1], nextPageAllCommitIds); + + if (previousCommitIndex !== -1) { + allTagsAnchor[allTagsAnchor.length - 1].after(getCompareIcon(nextPageAllTags[previousCommitIndex], allTags[allTags.length - 1])); + break; } } +} - return -1; -}; - -const extractCommitIds = (allCommitIdsAnchor: HTMLAnchorElement[], commitRegExp: RegExp): string[] => { - return allCommitIdsAnchor.map((commitIdAnchor: HTMLAnchorElement): string => { - const [, commitId] = commitIdAnchor.pathname.match(commitRegExp)!; +const extractAnchorValues = (anchors: HTMLAnchorElement[], regexp: RegExp): string[] => { + return anchors.map((anchor: HTMLAnchorElement): string => { + const [, value] = anchor.pathname.match(regexp)!; - return commitId; + return value; }); } -const extractTagNames = (allTagsAnchor: HTMLAnchorElement[], tagRegExp: RegExp): string[] => { - return allTagsAnchor.map((tagAnchor: HTMLAnchorElement): string => { - const [, tagName] = tagAnchor.pathname.match(tagRegExp)!; +const getPreviousTagCommitIndex = (startIndex: number, commitId: string, allCommitIds: string[]) => { + for (let i = startIndex; i < allCommitIds.length; i++) { + if (allCommitIds[i] !== commitId) { + return i; + } + } - return tagName; - }); -} + return -1; +}; + +// To select all links like "/facebook/react/commit/" +const getCommitIdSelector = (): string => { + const {ownerName, repoName} = getOwnerAndRepo(); -const getCommitIdSelector = (ownerName: string, repoName: string): string => { const commitAnchorSelector = `a[href^="/${ownerName}/${repoName}/commit/"]`; if (isReleasesListPage()) { @@ -88,7 +89,9 @@ const getCommitIdSelector = (ownerName: string, repoName: string): string => { } // To select all links like "/facebook/react/releases/tag" -const getTagSelector = (ownerName: string, repoName: string): string => { +const getTagSelector = (): string => { + const {ownerName, repoName} = getOwnerAndRepo(); + const tagAnchorSelector = `a[href^="/${ownerName}/${repoName}/releases/tag"]`; if (isReleasesListPage()) { @@ -102,18 +105,14 @@ const getTagSelector = (ownerName: string, repoName: string): string => { return tagAnchorSelector; } -const isReleasesListPage = () => { - return /^(releases)/.test(getRepoPath()!); -} +const isReleasesListPage = () => /^(releases)/.test(getRepoPath()!); -const isTagsListPage = () => { - return /^(tags)/.test(getRepoPath()!); -} +const isTagsListPage = () => /^(tags)/.test(getRepoPath()!); -const appendCompareIcon = (anchor: HTMLAnchorElement, prevTag: string, nextTag: string): void => { +const getCompareIcon = (prevTag: string, nextTag: string): HTMLSpanElement => { const {ownerName, repoName} = getOwnerAndRepo(); - anchor.after( + return ( @@ -122,12 +121,6 @@ const appendCompareIcon = (anchor: HTMLAnchorElement, prevTag: string, nextTag: ) } -const extractTagName = (tagPathname: string, regex: RegExp): string => { - const [, tag] = tagPathname.match(regex)!; - - return tag; -}; - features.add({ id: 'what-changed-since-previous-release', include: [ From 721b555c0d3682ce7dcdb0d307d582e851a8ffa0 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 02:14:54 +0530 Subject: [PATCH 06/54] Considering the namespaced tags The compare link is generated as follows 1. We find a commit having diffrent commit hash. 2. Once such a commit is found, we check the namespace. If namespaces are same, we use that tag as the previous tag else we try to look further for tag of same namespace. 3. If tag having same namespace is not found on the current page, we use the next commit having different hash. 4. For the last tag on the page, we fetch the next page and follow the same process as above. --- .../what-changed-since-previous-release.tsx | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 41f864e5a88..f90c3adc0e2 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -23,7 +23,7 @@ async function init(): Promise { const allCommitIds = extractAnchorValues([...select.all(getCommitIdSelector())], commitRegExp); for (let index = 0; index < allTags.length - 1; index++) { - const previousCommitIndex = getPreviousTagCommitIndex(index + 1, allCommitIds[index], allCommitIds); + const previousCommitIndex = getPreviousTagIndex(index + 1, allCommitIds[index], allCommitIds, allTags[index], allTags); if (previousCommitIndex !== -1) { allTagsAnchor[index].after(getCompareIcon(allTags[previousCommitIndex], allTags[index])); @@ -41,10 +41,10 @@ async function init(): Promise { const nextPageAllTagsAnchor = [...select.all(getTagSelector(), nextPage)]; const nextPageAllTags = extractAnchorValues(nextPageAllTagsAnchor, tagRegExp); - const nextPageAllCommitIds = extractAnchorValues([...select.all(getCommitIdSelector())], commitRegExp); + const nextPageAllCommitIds = extractAnchorValues([...select.all(getCommitIdSelector(), nextPage)], commitRegExp); for (let index = 0; index < nextPageAllTags.length; index++) { - const previousCommitIndex = getPreviousTagCommitIndex(index, allCommitIds[allCommitIds.length - 1], nextPageAllCommitIds); + const previousCommitIndex = getPreviousTagIndex(index, allCommitIds[allCommitIds.length - 1], nextPageAllCommitIds, allTags[allTags.length - 1], nextPageAllTags); if (previousCommitIndex !== -1) { allTagsAnchor[allTagsAnchor.length - 1].after(getCompareIcon(nextPageAllTags[previousCommitIndex], allTags[allTags.length - 1])); @@ -57,19 +57,46 @@ const extractAnchorValues = (anchors: HTMLAnchorElement[], regexp: RegExp): stri return anchors.map((anchor: HTMLAnchorElement): string => { const [, value] = anchor.pathname.match(regexp)!; - return value; + return decodeURIComponent(value); }); } -const getPreviousTagCommitIndex = (startIndex: number, commitId: string, allCommitIds: string[]) => { +const getPreviousTagIndex = ( + startIndex: number, + commitId: string, + allCommitIds: string[], + tag: string, + allTags: string[] +) => { + let index = -1; + for (let i = startIndex; i < allCommitIds.length; i++) { - if (allCommitIds[i] !== commitId) { + if (allCommitIds[i] === commitId) { + continue; + } + + if (isSameNameSpaceTag(allTags[i], tag)) { return i; } + + index = i; + } + + return index; +} + +const isSameNameSpaceTag = (tag1: string, tag2: string) => { + if (tag1.indexOf('@') === -1 || tag2.indexOf('@') === -1) { + return false; } - return -1; -}; + const namespaceRegex = /(.*)@[0-9.]*/; + + const [, tagOneNameSpace = ''] = tag1.match(namespaceRegex)! || []; + const [, tagTwoNameSpace = ''] = tag2.match(namespaceRegex)! || []; + + return tagOneNameSpace === tagTwoNameSpace; +} // To select all links like "/facebook/react/commit/" const getCommitIdSelector = (): string => { From b3200cd8be92840fbf9c4ea0a130850e9e502e9d Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 02:38:12 +0530 Subject: [PATCH 07/54] Move page detection functions to page-detect.ts --- source/libs/page-detect.ts | 4 ++++ test/page-detect.ts | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/source/libs/page-detect.ts b/source/libs/page-detect.ts index 2efe99287a3..bea3c53d061 100644 --- a/source/libs/page-detect.ts +++ b/source/libs/page-detect.ts @@ -95,6 +95,10 @@ export const isTrending = (): boolean => location.pathname === '/trending' || lo export const isUserProfile = (): boolean => select.exists('.user-profile-nav'); +export const isReleasesListPage = (): boolean => /^(releases)/.test(getRepoPath()!); + +export const isTagsListPage = (): boolean => /^(tags)/.test(getRepoPath()!); + export const hasComments = (): boolean => isPR() || isIssue() || diff --git a/test/page-detect.ts b/test/page-detect.ts index 9bb540c80fb..c0f9a3728e7 100644 --- a/test/page-detect.ts +++ b/test/page-detect.ts @@ -376,3 +376,21 @@ test('isRepoSearch', urlMatcherMacro, pageDetect.isRepoSearch, [ 'https://github.com/sindresorhus/search', 'https://github.com/search' ]); + +test('isReleasesListPage', urlMatcherMacro, pageDetect.isReleasesListPage, [ + 'https://github.com/sindresorhus/refined-github/releases', + 'https://github.com/sindresorhus/refined-github/releases/tag/v1.0.0-beta.4', + 'https://github.com/sindresorhus/refined-github/releases/tag/0.2.1' +], [ + 'https://github.com/sindresorhus/refined-github', + 'https://github.com/sindresorhus/refined-github/graphs' +]); + +test('isTagsListPage', urlMatcherMacro, pageDetect.isTagsListPage, [ + 'https://github.com/sindresorhus/refined-github/tags' +], [ + 'https://github.com/sindresorhus/refined-github', + 'https://github.com/sindresorhus/refined-github/graphs', + 'https://github.com/sindresorhus/refined-github/releases/tag/v1.0.0-beta.4', + 'https://github.com/sindresorhus/refined-github/releases/tag/0.2.1' +]); From 4d21eeab2073adf20bf2e815b6145693607f9d42 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 02:38:55 +0530 Subject: [PATCH 08/54] Lint fixes and minor UX improvement --- .../what-changed-since-previous-release.css | 1 + .../what-changed-since-previous-release.tsx | 45 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/source/features/what-changed-since-previous-release.css b/source/features/what-changed-since-previous-release.css index faf7be01c1c..f1642199357 100644 --- a/source/features/what-changed-since-previous-release.css +++ b/source/features/what-changed-since-previous-release.css @@ -5,4 +5,5 @@ .rgh-what-changed { margin-left: 5px; + cursor: pointer; } diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index f90c3adc0e2..3c0fbe0435a 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -2,7 +2,8 @@ import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; -import {getOwnerAndRepo, getRepoPath} from '../libs/utils'; +import {getOwnerAndRepo} from '../libs/utils'; +import {isTagsListPage, isReleasesListPage} from '../libs/page-detect'; async function init(): Promise { if (select.exists('.blankslate')) { @@ -12,10 +13,10 @@ async function init(): Promise { const {ownerName, repoName} = getOwnerAndRepo(); // To extract the tag "v16.8.6" from links like "/facebook/react/releases/tag/v16.8.6" - const tagRegExp = new RegExp(`\/${ownerName}\/${repoName}\/releases\/tag\/(.*)`); + const tagRegExp = new RegExp(`/${ownerName}/${repoName}/releases/tag/(.*)`); // To extract the commit hash from links like "/facebook/react/commit/92a1d8feac32d03ab5ea6ac13ae4941f6ae93b54" - const commitRegExp = new RegExp(`\/${ownerName}\/${repoName}\/commit\/([0-9a-f]{5,40})`); + const commitRegExp = new RegExp(`/${ownerName}/${repoName}/commit/([0-9a-f]{5,40})`); const allTagsAnchor = [...select.all(getTagSelector())]; const allTags = extractAnchorValues(allTagsAnchor, tagRegExp); @@ -59,7 +60,7 @@ const extractAnchorValues = (anchors: HTMLAnchorElement[], regexp: RegExp): stri return decodeURIComponent(value); }); -} +}; const getPreviousTagIndex = ( startIndex: number, @@ -67,7 +68,7 @@ const getPreviousTagIndex = ( allCommitIds: string[], tag: string, allTags: string[] -) => { +): number => { let index = -1; for (let i = startIndex; i < allCommitIds.length; i++) { @@ -79,14 +80,16 @@ const getPreviousTagIndex = ( return i; } - index = i; + if (index === -1) { + index = i; + } } return index; -} +}; -const isSameNameSpaceTag = (tag1: string, tag2: string) => { - if (tag1.indexOf('@') === -1 || tag2.indexOf('@') === -1) { +const isSameNameSpaceTag = (tag1: string, tag2: string): boolean => { + if (!tag1.includes('@') || !tag2.includes('@')) { return false; } @@ -96,7 +99,7 @@ const isSameNameSpaceTag = (tag1: string, tag2: string) => { const [, tagTwoNameSpace = ''] = tag2.match(namespaceRegex)! || []; return tagOneNameSpace === tagTwoNameSpace; -} +}; // To select all links like "/facebook/react/commit/" const getCommitIdSelector = (): string => { @@ -113,7 +116,7 @@ const getCommitIdSelector = (): string => { } return commitAnchorSelector; -} +}; // To select all links like "/facebook/react/releases/tag" const getTagSelector = (): string => { @@ -130,23 +133,19 @@ const getTagSelector = (): string => { } return tagAnchorSelector; -} - -const isReleasesListPage = () => /^(releases)/.test(getRepoPath()!); +}; -const isTagsListPage = () => /^(tags)/.test(getRepoPath()!); - -const getCompareIcon = (prevTag: string, nextTag: string): HTMLSpanElement => { +const getCompareIcon = (prevTag: string, nextTag: string): HTMLElement => { const {ownerName, repoName} = getOwnerAndRepo(); return ( - - + + - - - ) -} + + + ); +}; features.add({ id: 'what-changed-since-previous-release', From 9c5f60b9a600e666ceaeb85836e63e2277bb47d8 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 02:45:00 +0530 Subject: [PATCH 09/54] Modify selector to make it work with single release page --- source/features/what-changed-since-previous-release.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 3c0fbe0435a..fb7a64a1390 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -108,7 +108,7 @@ const getCommitIdSelector = (): string => { const commitAnchorSelector = `a[href^="/${ownerName}/${repoName}/commit/"]`; if (isReleasesListPage()) { - return `.release-entry .release-main-section .commit > ul ${commitAnchorSelector}, .release-entry > .release > div:first-child > ul ${commitAnchorSelector}`; + return `.release-entry .release-main-section .commit > ul ${commitAnchorSelector}, .release > div:first-child > ul ${commitAnchorSelector}`; } if (isTagsListPage()) { From 117d04f06a7ba185a5310ac7d807f3101e7a1464 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 22:15:47 +0530 Subject: [PATCH 10/54] Comparing tags in a better way --- .../what-changed-since-previous-release.tsx | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index fb7a64a1390..86fc44d1d47 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -76,7 +76,7 @@ const getPreviousTagIndex = ( continue; } - if (isSameNameSpaceTag(allTags[i], tag)) { + if (isOfSameHierarchy(allTags[i], tag) && isSameTagNameSpace(allTags[i], tag)) { return i; } @@ -88,18 +88,33 @@ const getPreviousTagIndex = ( return index; }; -const isSameNameSpaceTag = (tag1: string, tag2: string): boolean => { - if (!tag1.includes('@') || !tag2.includes('@')) { +const isOfSameHierarchy = (tag1: string, tag2: string): boolean => { + const isTag1Hierarchical = tag1.includes('/'); + const isTag2Hierarchical = tag2.includes('/'); + + if (isTag1Hierarchical && !isTag2Hierarchical) { return false; } - const namespaceRegex = /(.*)@[0-9.]*/; + if (!isTag1Hierarchical && isTag2Hierarchical) { + return false; + } + + if (!isTag1Hierarchical && !isTag2Hierarchical) { + return true; + } + + return tag1.substring(0, tag1.lastIndexOf("/") + 1) === tag2.substring(0, tag2.lastIndexOf("/") + 1); +} + +const isSameTagNameSpace = (tag1: string, tag2: string): boolean => { + const namespaceRegex = /(.*)@(.)*/; - const [, tagOneNameSpace = ''] = tag1.match(namespaceRegex)! || []; - const [, tagTwoNameSpace = ''] = tag2.match(namespaceRegex)! || []; + const [, tagOneNameSpace = ''] = tag1.match(namespaceRegex) || []; + const [, tagTwoNameSpace = ''] = tag2.match(namespaceRegex) || []; return tagOneNameSpace === tagTwoNameSpace; -}; +} // To select all links like "/facebook/react/commit/" const getCommitIdSelector = (): string => { @@ -139,7 +154,7 @@ const getCompareIcon = (prevTag: string, nextTag: string): HTMLElement => { const {ownerName, repoName} = getOwnerAndRepo(); return ( - + From 53ba546481ac41674ba0aef5b479839b23ae4468 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 22:27:53 +0530 Subject: [PATCH 11/54] Use regex to compare tag hierarchy --- .../what-changed-since-previous-release.tsx | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 86fc44d1d47..3d723635de3 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -89,23 +89,21 @@ const getPreviousTagIndex = ( }; const isOfSameHierarchy = (tag1: string, tag2: string): boolean => { - const isTag1Hierarchical = tag1.includes('/'); - const isTag2Hierarchical = tag2.includes('/'); + const hierarchyRegex = /.*(\/)/; - if (isTag1Hierarchical && !isTag2Hierarchical) { - return false; - } + const [tagOneHierarchy = ''] = tag1.match(hierarchyRegex) || []; + const [tagTwoHierarchy = ''] = tag2.match(hierarchyRegex) || []; - if (!isTag1Hierarchical && isTag2Hierarchical) { + if ((!tagOneHierarchy && tagTwoHierarchy) || (tagOneHierarchy && !tagTwoHierarchy)) { return false; } - if (!isTag1Hierarchical && !isTag2Hierarchical) { + if (!tagOneHierarchy && !tagTwoHierarchy) { return true; } - return tag1.substring(0, tag1.lastIndexOf("/") + 1) === tag2.substring(0, tag2.lastIndexOf("/") + 1); -} + return tagOneHierarchy === tagTwoHierarchy; +}; const isSameTagNameSpace = (tag1: string, tag2: string): boolean => { const namespaceRegex = /(.*)@(.)*/; @@ -114,7 +112,7 @@ const isSameTagNameSpace = (tag1: string, tag2: string): boolean => { const [, tagTwoNameSpace = ''] = tag2.match(namespaceRegex) || []; return tagOneNameSpace === tagTwoNameSpace; -} +}; // To select all links like "/facebook/react/commit/" const getCommitIdSelector = (): string => { From f56d01e1945ba79a135d87f58f81654a94a2feff Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 22:31:56 +0530 Subject: [PATCH 12/54] Rename function --- .../features/what-changed-since-previous-release.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 3d723635de3..ae785de7283 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -19,9 +19,9 @@ async function init(): Promise { const commitRegExp = new RegExp(`/${ownerName}/${repoName}/commit/([0-9a-f]{5,40})`); const allTagsAnchor = [...select.all(getTagSelector())]; - const allTags = extractAnchorValues(allTagsAnchor, tagRegExp); + const allTags = extractValuesFromPathname(allTagsAnchor, tagRegExp); - const allCommitIds = extractAnchorValues([...select.all(getCommitIdSelector())], commitRegExp); + const allCommitIds = extractValuesFromPathname([...select.all(getCommitIdSelector())], commitRegExp); for (let index = 0; index < allTags.length - 1; index++) { const previousCommitIndex = getPreviousTagIndex(index + 1, allCommitIds[index], allCommitIds, allTags[index], allTags); @@ -40,9 +40,9 @@ async function init(): Promise { const nextPage = await fetchDom(nextPageLink.href); const nextPageAllTagsAnchor = [...select.all(getTagSelector(), nextPage)]; - const nextPageAllTags = extractAnchorValues(nextPageAllTagsAnchor, tagRegExp); + const nextPageAllTags = extractValuesFromPathname(nextPageAllTagsAnchor, tagRegExp); - const nextPageAllCommitIds = extractAnchorValues([...select.all(getCommitIdSelector(), nextPage)], commitRegExp); + const nextPageAllCommitIds = extractValuesFromPathname([...select.all(getCommitIdSelector(), nextPage)], commitRegExp); for (let index = 0; index < nextPageAllTags.length; index++) { const previousCommitIndex = getPreviousTagIndex(index, allCommitIds[allCommitIds.length - 1], nextPageAllCommitIds, allTags[allTags.length - 1], nextPageAllTags); @@ -54,7 +54,7 @@ async function init(): Promise { } } -const extractAnchorValues = (anchors: HTMLAnchorElement[], regexp: RegExp): string[] => { +const extractValuesFromPathname = (anchors: HTMLAnchorElement[], regexp: RegExp): string[] => { return anchors.map((anchor: HTMLAnchorElement): string => { const [, value] = anchor.pathname.match(regexp)!; From fc338771dd4e3505fb304c9cbaef5f755ee2b90f Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 29 Apr 2019 23:58:01 +0530 Subject: [PATCH 13/54] Display compare link on single tag pages --- .../what-changed-since-previous-release.tsx | 19 ++++++++++++------- source/libs/page-detect.ts | 2 ++ test/page-detect.ts | 10 ++++++++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index ae785de7283..8be2f472f2a 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -3,7 +3,7 @@ import select from 'select-dom'; import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; import {getOwnerAndRepo} from '../libs/utils'; -import {isTagsListPage, isReleasesListPage} from '../libs/page-detect'; +import {isTagsListPage, isReleasesListPage, isSingleTagPage} from '../libs/page-detect'; async function init(): Promise { if (select.exists('.blankslate')) { @@ -20,7 +20,6 @@ async function init(): Promise { const allTagsAnchor = [...select.all(getTagSelector())]; const allTags = extractValuesFromPathname(allTagsAnchor, tagRegExp); - const allCommitIds = extractValuesFromPathname([...select.all(getCommitIdSelector())], commitRegExp); for (let index = 0; index < allTags.length - 1; index++) { @@ -31,13 +30,19 @@ async function init(): Promise { } } - const nextPageLink = select('.pagination a:last-child'); + let nextPage; - if (!nextPageLink) { - return; - } + if (isSingleTagPage()) { + nextPage = await fetchDom(`/${ownerName}/${repoName}/releases?after=${allTags[0]}`); + } else { + const nextPageLink = select('.pagination a:last-child'); - const nextPage = await fetchDom(nextPageLink.href); + if (!nextPageLink) { + return; + } + + nextPage = await fetchDom(nextPageLink.href); + } const nextPageAllTagsAnchor = [...select.all(getTagSelector(), nextPage)]; const nextPageAllTags = extractValuesFromPathname(nextPageAllTagsAnchor, tagRegExp); diff --git a/source/libs/page-detect.ts b/source/libs/page-detect.ts index bea3c53d061..5265ec89a9d 100644 --- a/source/libs/page-detect.ts +++ b/source/libs/page-detect.ts @@ -99,6 +99,8 @@ export const isReleasesListPage = (): boolean => /^(releases)/.test(getRepoPath( export const isTagsListPage = (): boolean => /^(tags)/.test(getRepoPath()!); +export const isSingleTagPage = (): boolean => /^(releases\/tag)/.test(getRepoPath()!); + export const hasComments = (): boolean => isPR() || isIssue() || diff --git a/test/page-detect.ts b/test/page-detect.ts index c0f9a3728e7..f2d6f99f0bb 100644 --- a/test/page-detect.ts +++ b/test/page-detect.ts @@ -394,3 +394,13 @@ test('isTagsListPage', urlMatcherMacro, pageDetect.isTagsListPage, [ 'https://github.com/sindresorhus/refined-github/releases/tag/v1.0.0-beta.4', 'https://github.com/sindresorhus/refined-github/releases/tag/0.2.1' ]); + +test('isSingleTagPage', urlMatcherMacro, pageDetect.isSingleTagPage, [ + 'https://github.com/sindresorhus/refined-github/releases/tag/v1.0.0-beta.4', + 'https://github.com/sindresorhus/refined-github/releases/tag/0.2.1' +], [ + 'https://github.com/sindresorhus/refined-github/tags', + 'https://github.com/sindresorhus/refined-github/releases', + 'https://github.com/sindresorhus/refined-github', + 'https://github.com/sindresorhus/refined-github/graphs' +]); From b9d1aeefbfa5decfe23c4a5546b376512c24045a Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Tue, 30 Apr 2019 00:54:00 +0530 Subject: [PATCH 14/54] Few renames --- .../features/what-changed-since-previous-release.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 8be2f472f2a..a122a88300b 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -26,7 +26,7 @@ async function init(): Promise { const previousCommitIndex = getPreviousTagIndex(index + 1, allCommitIds[index], allCommitIds, allTags[index], allTags); if (previousCommitIndex !== -1) { - allTagsAnchor[index].after(getCompareIcon(allTags[previousCommitIndex], allTags[index])); + allTagsAnchor[index].after(getTagComparisonLink(allTags[previousCommitIndex], allTags[index])); } } @@ -50,10 +50,10 @@ async function init(): Promise { const nextPageAllCommitIds = extractValuesFromPathname([...select.all(getCommitIdSelector(), nextPage)], commitRegExp); for (let index = 0; index < nextPageAllTags.length; index++) { - const previousCommitIndex = getPreviousTagIndex(index, allCommitIds[allCommitIds.length - 1], nextPageAllCommitIds, allTags[allTags.length - 1], nextPageAllTags); + const previousTagIndex = getPreviousTagIndex(index, allCommitIds[allCommitIds.length - 1], nextPageAllCommitIds, allTags[allTags.length - 1], nextPageAllTags); - if (previousCommitIndex !== -1) { - allTagsAnchor[allTagsAnchor.length - 1].after(getCompareIcon(nextPageAllTags[previousCommitIndex], allTags[allTags.length - 1])); + if (previousTagIndex !== -1) { + allTagsAnchor[allTagsAnchor.length - 1].after(getTagComparisonLink(nextPageAllTags[previousTagIndex], allTags[allTags.length - 1])); break; } } @@ -153,7 +153,7 @@ const getTagSelector = (): string => { return tagAnchorSelector; }; -const getCompareIcon = (prevTag: string, nextTag: string): HTMLElement => { +const getTagComparisonLink = (prevTag: string, nextTag: string): HTMLElement => { const {ownerName, repoName} = getOwnerAndRepo(); return ( From 6baf0a6386580be2b003aeb4a0fdec96309bc380 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 01:20:02 +0530 Subject: [PATCH 15/54] Removed extra code 1. Simplified the regex 2. Simplified the tag and commit selectors and removed their unnecessary methods 3. Used the GitHub's diff icon for displaying comparison link 4. Better position for compare link --- .vscode/settings.json | 3 + .../what-changed-since-previous-release.css | 8 +- .../what-changed-since-previous-release.tsx | 73 ++++++------------- 3 files changed, 32 insertions(+), 52 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..55712c19f1d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/source/features/what-changed-since-previous-release.css b/source/features/what-changed-since-previous-release.css index f1642199357..5c9238010d7 100644 --- a/source/features/what-changed-since-previous-release.css +++ b/source/features/what-changed-since-previous-release.css @@ -3,7 +3,13 @@ display: none !important; } +.commit > ul > li.rgh-what-changed { + display: inline-block; + margin-top: 4px; + margin-right: 8px; +} + .rgh-what-changed { - margin-left: 5px; cursor: pointer; + font-size: 12px; } diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index a122a88300b..78cf8da2889 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -3,7 +3,8 @@ import select from 'select-dom'; import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; import {getOwnerAndRepo} from '../libs/utils'; -import {isTagsListPage, isReleasesListPage, isSingleTagPage} from '../libs/page-detect'; +import {isSingleTagPage} from '../libs/page-detect'; +import {diff} from '../libs/icons'; async function init(): Promise { if (select.exists('.blankslate')) { @@ -13,20 +14,26 @@ async function init(): Promise { const {ownerName, repoName} = getOwnerAndRepo(); // To extract the tag "v16.8.6" from links like "/facebook/react/releases/tag/v16.8.6" - const tagRegExp = new RegExp(`/${ownerName}/${repoName}/releases/tag/(.*)`); + const tagRegExp = /releases\/tag\/(.*)$/; // To extract the commit hash from links like "/facebook/react/commit/92a1d8feac32d03ab5ea6ac13ae4941f6ae93b54" - const commitRegExp = new RegExp(`/${ownerName}/${repoName}/commit/([0-9a-f]{5,40})`); + const commitRegExp = /commit\/([0-9a-f]{40})$/; - const allTagsAnchor = [...select.all(getTagSelector())]; - const allTags = extractValuesFromPathname(allTagsAnchor, tagRegExp); - const allCommitIds = extractValuesFromPathname([...select.all(getCommitIdSelector())], commitRegExp); + const tagAnchorSelector = `a[href^="/${ownerName}/${repoName}/releases/tag"]`; + const tagSelector = `h4.commit-title ${tagAnchorSelector}, .commit .release-header ${tagAnchorSelector}`; + + const commitAnchorSelector = `a[href^="/${ownerName}/${repoName}/commit/"]`; + const commitIdSelector = `.commit > ul ${commitAnchorSelector}, .release > div:first-child > ul ${commitAnchorSelector}`; + + const allTags = extractValuesFromPathname(select.all(tagSelector), tagRegExp); + const allCommitIdsAnchor = select.all(commitIdSelector); + const allCommitIds = extractValuesFromPathname(allCommitIdsAnchor, commitRegExp); for (let index = 0; index < allTags.length - 1; index++) { const previousCommitIndex = getPreviousTagIndex(index + 1, allCommitIds[index], allCommitIds, allTags[index], allTags); if (previousCommitIndex !== -1) { - allTagsAnchor[index].after(getTagComparisonLink(allTags[previousCommitIndex], allTags[index])); + allCommitIdsAnchor[index].parentElement!.parentElement!.append(getTagComparisonLink(allTags[previousCommitIndex], allTags[index])); } } @@ -44,16 +51,14 @@ async function init(): Promise { nextPage = await fetchDom(nextPageLink.href); } - const nextPageAllTagsAnchor = [...select.all(getTagSelector(), nextPage)]; - const nextPageAllTags = extractValuesFromPathname(nextPageAllTagsAnchor, tagRegExp); - - const nextPageAllCommitIds = extractValuesFromPathname([...select.all(getCommitIdSelector(), nextPage)], commitRegExp); + const nextPageAllTags = extractValuesFromPathname(select.all(tagSelector, nextPage), tagRegExp); + const nextPageAllCommitIds = extractValuesFromPathname(select.all(commitIdSelector, nextPage), commitRegExp); for (let index = 0; index < nextPageAllTags.length; index++) { const previousTagIndex = getPreviousTagIndex(index, allCommitIds[allCommitIds.length - 1], nextPageAllCommitIds, allTags[allTags.length - 1], nextPageAllTags); if (previousTagIndex !== -1) { - allTagsAnchor[allTagsAnchor.length - 1].after(getTagComparisonLink(nextPageAllTags[previousTagIndex], allTags[allTags.length - 1])); + allCommitIdsAnchor[allCommitIdsAnchor.length - 1].parentElement!.parentElement!.append(getTagComparisonLink(nextPageAllTags[previousTagIndex], allTags[allTags.length - 1])); break; } } @@ -119,49 +124,15 @@ const isSameTagNameSpace = (tag1: string, tag2: string): boolean => { return tagOneNameSpace === tagTwoNameSpace; }; -// To select all links like "/facebook/react/commit/" -const getCommitIdSelector = (): string => { - const {ownerName, repoName} = getOwnerAndRepo(); - - const commitAnchorSelector = `a[href^="/${ownerName}/${repoName}/commit/"]`; - - if (isReleasesListPage()) { - return `.release-entry .release-main-section .commit > ul ${commitAnchorSelector}, .release > div:first-child > ul ${commitAnchorSelector}`; - } - - if (isTagsListPage()) { - return `.commit > ul ${commitAnchorSelector}`; - } - - return commitAnchorSelector; -}; - -// To select all links like "/facebook/react/releases/tag" -const getTagSelector = (): string => { - const {ownerName, repoName} = getOwnerAndRepo(); - - const tagAnchorSelector = `a[href^="/${ownerName}/${repoName}/releases/tag"]`; - - if (isReleasesListPage()) { - return `.release-main-section h4.commit-title ${tagAnchorSelector}, .release-main-section .release-header ${tagAnchorSelector}`; - } - - if (isTagsListPage()) { - return `h4.commit-title > ${tagAnchorSelector}`; - } - - return tagAnchorSelector; -}; - const getTagComparisonLink = (prevTag: string, nextTag: string): HTMLElement => { const {ownerName, repoName} = getOwnerAndRepo(); return ( - - - - - +
  • + +
    {diff()}
    compare +
    +
  • ); }; From 4ff927a6c1e8257f5f8c2d153351318cdf58b566 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 01:58:16 +0530 Subject: [PATCH 16/54] Further simplify the code 1. Removed conditional checks before looking for previous tags. All tags are now treated equally whether they are on releases, tag listing or single tag page. 2. Use the single loop to go through the tags irrespective of their index. It also improved the probability of finding the previous tag to compare as we now look into the next page for all the tags. --- .../what-changed-since-previous-release.tsx | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 78cf8da2889..7f0b5df615d 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -11,57 +11,42 @@ async function init(): Promise { return false; } - const {ownerName, repoName} = getOwnerAndRepo(); - // To extract the tag "v16.8.6" from links like "/facebook/react/releases/tag/v16.8.6" const tagRegExp = /releases\/tag\/(.*)$/; // To extract the commit hash from links like "/facebook/react/commit/92a1d8feac32d03ab5ea6ac13ae4941f6ae93b54" const commitRegExp = /commit\/([0-9a-f]{40})$/; - const tagAnchorSelector = `a[href^="/${ownerName}/${repoName}/releases/tag"]`; - const tagSelector = `h4.commit-title ${tagAnchorSelector}, .commit .release-header ${tagAnchorSelector}`; - - const commitAnchorSelector = `a[href^="/${ownerName}/${repoName}/commit/"]`; - const commitIdSelector = `.commit > ul ${commitAnchorSelector}, .release > div:first-child > ul ${commitAnchorSelector}`; + const tagSelector = 'h4.commit-title a[href*="/releases/tag"], .commit .release-header a[href*="/releases/tag"]'; + const commitIdSelector = '.commit > ul a[href*="/commit/"], .release > div:first-child > ul a[href*="/commit/"]'; const allTags = extractValuesFromPathname(select.all(tagSelector), tagRegExp); const allCommitIdsAnchor = select.all(commitIdSelector); const allCommitIds = extractValuesFromPathname(allCommitIdsAnchor, commitRegExp); - for (let index = 0; index < allTags.length - 1; index++) { + const nextPageLink = select('.pagination a:last-child'); + const nextPage = nextPageLink ? await fetchDom(nextPageLink.href) : await getNextPageForSinglePageTag(allTags[0]); + + allTags.push(...extractValuesFromPathname(select.all(tagSelector, nextPage || document), tagRegExp)); + allCommitIds.push(...extractValuesFromPathname(select.all(commitIdSelector, nextPage || document), commitRegExp)); + + for (let index = 0; index < allCommitIdsAnchor.length; index++) { const previousCommitIndex = getPreviousTagIndex(index + 1, allCommitIds[index], allCommitIds, allTags[index], allTags); if (previousCommitIndex !== -1) { allCommitIdsAnchor[index].parentElement!.parentElement!.append(getTagComparisonLink(allTags[previousCommitIndex], allTags[index])); } } +} - let nextPage; - - if (isSingleTagPage()) { - nextPage = await fetchDom(`/${ownerName}/${repoName}/releases?after=${allTags[0]}`); - } else { - const nextPageLink = select('.pagination a:last-child'); - - if (!nextPageLink) { - return; - } - - nextPage = await fetchDom(nextPageLink.href); +const getNextPageForSinglePageTag = async (singleTag: string): Promise => { + if (!isSingleTagPage()) { + return; } - const nextPageAllTags = extractValuesFromPathname(select.all(tagSelector, nextPage), tagRegExp); - const nextPageAllCommitIds = extractValuesFromPathname(select.all(commitIdSelector, nextPage), commitRegExp); - - for (let index = 0; index < nextPageAllTags.length; index++) { - const previousTagIndex = getPreviousTagIndex(index, allCommitIds[allCommitIds.length - 1], nextPageAllCommitIds, allTags[allTags.length - 1], nextPageAllTags); + const {ownerName, repoName} = getOwnerAndRepo(); - if (previousTagIndex !== -1) { - allCommitIdsAnchor[allCommitIdsAnchor.length - 1].parentElement!.parentElement!.append(getTagComparisonLink(nextPageAllTags[previousTagIndex], allTags[allTags.length - 1])); - break; - } - } + return fetchDom(`/${ownerName}/${repoName}/releases?after=${singleTag}`); } const extractValuesFromPathname = (anchors: HTMLAnchorElement[], regexp: RegExp): string[] => { From 73b4247569f19deb505516b1e5cf13f7ac165ff0 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 02:23:17 +0530 Subject: [PATCH 17/54] Minor style fixes --- source/features/what-changed-since-previous-release.css | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/features/what-changed-since-previous-release.css b/source/features/what-changed-since-previous-release.css index 5c9238010d7..4287b690223 100644 --- a/source/features/what-changed-since-previous-release.css +++ b/source/features/what-changed-since-previous-release.css @@ -1,14 +1,13 @@ -.release-entry .hidden-text-expander, -.commit .hidden-text-expander { - display: none !important; -} - .commit > ul > li.rgh-what-changed { display: inline-block; margin-top: 4px; margin-right: 8px; } +.release > div:first-child > ul > li.rgh-what-changed { + margin-bottom: 4px; +} + .rgh-what-changed { cursor: pointer; font-size: 12px; From 7a4ccdd2864a31ec342b9054aed1d7e31ac291bf Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 02:24:11 +0530 Subject: [PATCH 18/54] Minor changes and few renames --- .../what-changed-since-previous-release.tsx | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 7f0b5df615d..f1cb974c83a 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -27,28 +27,20 @@ async function init(): Promise { const nextPageLink = select('.pagination a:last-child'); const nextPage = nextPageLink ? await fetchDom(nextPageLink.href) : await getNextPageForSinglePageTag(allTags[0]); - allTags.push(...extractValuesFromPathname(select.all(tagSelector, nextPage || document), tagRegExp)); - allCommitIds.push(...extractValuesFromPathname(select.all(commitIdSelector, nextPage || document), commitRegExp)); + if (nextPage) { + allTags.push(...extractValuesFromPathname(select.all(tagSelector, nextPage), tagRegExp)); + allCommitIds.push(...extractValuesFromPathname(select.all(commitIdSelector, nextPage), commitRegExp)); + } for (let index = 0; index < allCommitIdsAnchor.length; index++) { - const previousCommitIndex = getPreviousTagIndex(index + 1, allCommitIds[index], allCommitIds, allTags[index], allTags); + const previousTagIndex = getPreviousTagIndex(index + 1, allCommitIds[index], allCommitIds, allTags[index], allTags); - if (previousCommitIndex !== -1) { - allCommitIdsAnchor[index].parentElement!.parentElement!.append(getTagComparisonLink(allTags[previousCommitIndex], allTags[index])); + if (previousTagIndex !== -1) { + allCommitIdsAnchor[index].parentElement!.parentElement!.append(getTagComparisonLink(allTags[previousTagIndex], allTags[index])); } } } -const getNextPageForSinglePageTag = async (singleTag: string): Promise => { - if (!isSingleTagPage()) { - return; - } - - const {ownerName, repoName} = getOwnerAndRepo(); - - return fetchDom(`/${ownerName}/${repoName}/releases?after=${singleTag}`); -} - const extractValuesFromPathname = (anchors: HTMLAnchorElement[], regexp: RegExp): string[] => { return anchors.map((anchor: HTMLAnchorElement): string => { const [, value] = anchor.pathname.match(regexp)!; @@ -57,13 +49,17 @@ const extractValuesFromPathname = (anchors: HTMLAnchorElement[], regexp: RegExp) }); }; -const getPreviousTagIndex = ( - startIndex: number, - commitId: string, - allCommitIds: string[], - tag: string, - allTags: string[] -): number => { +const getNextPageForSinglePageTag = async (tag: string): Promise => { + if (!isSingleTagPage()) { + return; + } + + const {ownerName, repoName} = getOwnerAndRepo(); + + return fetchDom(`/${ownerName}/${repoName}/releases?after=${tag}`); +} + +const getPreviousTagIndex = (startIndex: number, commitId: string, allCommitIds: string[], tag: string, allTags: string[]): number => { let index = -1; for (let i = startIndex; i < allCommitIds.length; i++) { @@ -115,7 +111,7 @@ const getTagComparisonLink = (prevTag: string, nextTag: string): HTMLElement => return (
  • -
    {diff()}
    compare +
    {diff()}
    compare
  • ); From 6b24bc8f39bfb068025bb57096689830c3bce173 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 02:44:19 +0530 Subject: [PATCH 19/54] Lint fixes and remove unused code --- .../what-changed-since-previous-release.tsx | 2 +- source/libs/page-detect.ts | 4 ---- test/page-detect.ts | 18 ------------------ 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index f1cb974c83a..ba78e772b2c 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -57,7 +57,7 @@ const getNextPageForSinglePageTag = async (tag: string): Promise { let index = -1; diff --git a/source/libs/page-detect.ts b/source/libs/page-detect.ts index 8442e56d65f..524db6db932 100644 --- a/source/libs/page-detect.ts +++ b/source/libs/page-detect.ts @@ -97,10 +97,6 @@ export const isTrending = (): boolean => location.pathname === '/trending' || lo export const isUserProfile = (): boolean => select.exists('.user-profile-nav'); -export const isReleasesListPage = (): boolean => /^(releases)/.test(getRepoPath()!); - -export const isTagsListPage = (): boolean => /^(tags)/.test(getRepoPath()!); - export const isSingleTagPage = (): boolean => /^(releases\/tag)/.test(getRepoPath()!); export const hasComments = (): boolean => diff --git a/test/page-detect.ts b/test/page-detect.ts index 99e88102e8b..0821563c4b3 100644 --- a/test/page-detect.ts +++ b/test/page-detect.ts @@ -381,24 +381,6 @@ test('isRepoSearch', urlMatcherMacro, pageDetect.isRepoSearch, [ 'https://github.com/search' ]); -test('isReleasesListPage', urlMatcherMacro, pageDetect.isReleasesListPage, [ - 'https://github.com/sindresorhus/refined-github/releases', - 'https://github.com/sindresorhus/refined-github/releases/tag/v1.0.0-beta.4', - 'https://github.com/sindresorhus/refined-github/releases/tag/0.2.1' -], [ - 'https://github.com/sindresorhus/refined-github', - 'https://github.com/sindresorhus/refined-github/graphs' -]); - -test('isTagsListPage', urlMatcherMacro, pageDetect.isTagsListPage, [ - 'https://github.com/sindresorhus/refined-github/tags' -], [ - 'https://github.com/sindresorhus/refined-github', - 'https://github.com/sindresorhus/refined-github/graphs', - 'https://github.com/sindresorhus/refined-github/releases/tag/v1.0.0-beta.4', - 'https://github.com/sindresorhus/refined-github/releases/tag/0.2.1' -]); - test('isSingleTagPage', urlMatcherMacro, pageDetect.isSingleTagPage, [ 'https://github.com/sindresorhus/refined-github/releases/tag/v1.0.0-beta.4', 'https://github.com/sindresorhus/refined-github/releases/tag/0.2.1' From 484fe16843bf579bd01a98738992701b792dbfa1 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 02:47:29 +0530 Subject: [PATCH 20/54] =?UTF-8?q?=F0=9F=A4=A6=20Delete=20local=20file?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 55712c19f1d..00000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "typescript.tsdk": "node_modules/typescript/lib" -} \ No newline at end of file From 8ea9fea8ad2885365bc53d95f0ea8d6e3a22af9b Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 11:24:55 +0530 Subject: [PATCH 21/54] PR Feedback to improve the code and to make it more concise --- .../what-changed-since-previous-release.tsx | 49 ++++++------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index ba78e772b2c..24cdc7b71a4 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -33,10 +33,10 @@ async function init(): Promise { } for (let index = 0; index < allCommitIdsAnchor.length; index++) { - const previousTagIndex = getPreviousTagIndex(index + 1, allCommitIds[index], allCommitIds, allTags[index], allTags); + const previousTagIndex = getPreviousTagIndex(index, allCommitIds, allTags); if (previousTagIndex !== -1) { - allCommitIdsAnchor[index].parentElement!.parentElement!.append(getTagComparisonLink(allTags[previousTagIndex], allTags[index])); + allCommitIdsAnchor[index].closest('ul')!.append(getTagComparisonLink(allTags[previousTagIndex], allTags[index])); } } } @@ -59,51 +59,32 @@ const getNextPageForSinglePageTag = async (tag: string): Promise { - let index = -1; +const getPreviousTagIndex = (index: number, allCommitIds: string[], allTags: string[]): number => { + let prevTagIndex = -1; - for (let i = startIndex; i < allCommitIds.length; i++) { - if (allCommitIds[i] === commitId) { + for (let i = index + 1; i < allCommitIds.length; i++) { + if (allCommitIds[i] === allCommitIds[index]) { continue; } - if (isOfSameHierarchy(allTags[i], tag) && isSameTagNameSpace(allTags[i], tag)) { + if (doesNamespaceMatch(allTags[i], allTags[index])) { return i; } - if (index === -1) { - index = i; + if (prevTagIndex === -1) { + prevTagIndex = i; } } - return index; + return prevTagIndex; }; -const isOfSameHierarchy = (tag1: string, tag2: string): boolean => { - const hierarchyRegex = /.*(\/)/; +const doesNamespaceMatch = (tag1: string, tag2: string) => { + const [namespace1] = tag1.split(/@[^@]+$|^/); + const [namespace2] = tag2.split(/@[^@]+$|^/); - const [tagOneHierarchy = ''] = tag1.match(hierarchyRegex) || []; - const [tagTwoHierarchy = ''] = tag2.match(hierarchyRegex) || []; - - if ((!tagOneHierarchy && tagTwoHierarchy) || (tagOneHierarchy && !tagTwoHierarchy)) { - return false; - } - - if (!tagOneHierarchy && !tagTwoHierarchy) { - return true; - } - - return tagOneHierarchy === tagTwoHierarchy; -}; - -const isSameTagNameSpace = (tag1: string, tag2: string): boolean => { - const namespaceRegex = /(.*)@(.)*/; - - const [, tagOneNameSpace = ''] = tag1.match(namespaceRegex) || []; - const [, tagTwoNameSpace = ''] = tag2.match(namespaceRegex) || []; - - return tagOneNameSpace === tagTwoNameSpace; -}; + return namespace1 === namespace2; +} const getTagComparisonLink = (prevTag: string, nextTag: string): HTMLElement => { const {ownerName, repoName} = getOwnerAndRepo(); From be0d3b3d5726978d260a4f2d8ecdd606bde103e9 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 11:52:07 +0530 Subject: [PATCH 22/54] Simplified the regex and concise code --- source/features/what-changed-since-previous-release.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 24cdc7b71a4..6e51cf8ffd4 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -79,12 +79,7 @@ const getPreviousTagIndex = (index: number, allCommitIds: string[], allTags: str return prevTagIndex; }; -const doesNamespaceMatch = (tag1: string, tag2: string) => { - const [namespace1] = tag1.split(/@[^@]+$|^/); - const [namespace2] = tag2.split(/@[^@]+$|^/); - - return namespace1 === namespace2; -} +const doesNamespaceMatch = (tag1: string, tag2: string): boolean => tag1.split(/@[^@]+$/)[0] === tag2.split(/@[^@]+$/)[0]; const getTagComparisonLink = (prevTag: string, nextTag: string): HTMLElement => { const {ownerName, repoName} = getOwnerAndRepo(); From d5cb6b66488ce8419fdb5d89213bec8574bc0cd1 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 12:03:53 +0530 Subject: [PATCH 23/54] Import css file in the feature file --- source/content.ts | 1 - source/features/what-changed-since-previous-release.tsx | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/source/content.ts b/source/content.ts index a94a17f7128..cd48d152d48 100644 --- a/source/content.ts +++ b/source/content.ts @@ -114,7 +114,6 @@ import './features/hide-tips.css'; import './features/hide-readme-header.css'; import './features/hide-obvious-tooltips.css'; import './features/clean-discussions.css'; -import './features/what-changed-since-previous-release.css'; // Add global for easier debugging (window as any).select = select; diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index 6e51cf8ffd4..a818ddd6d6e 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -1,3 +1,4 @@ +import './what-changed-since-previous-release.css'; import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; From 123d47a6313ece1874b03fd0efbe42e4975f536e Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 12:09:13 +0530 Subject: [PATCH 24/54] Feature doc --- source/features/what-changed-since-previous-release.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/what-changed-since-previous-release.tsx index a818ddd6d6e..79e7d652e77 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/what-changed-since-previous-release.tsx @@ -1,3 +1,10 @@ +/** +This feature adds a compare link on each releases/tags/single tag page so that you can see +what has changed since the previous release. If the tags are namespaced then it tries to +get the previous release of the same namespaced tag. + +See it in action at: https://github.com/parcel-bundler/parcel/releases +*/ import './what-changed-since-previous-release.css'; import React from 'dom-chef'; import select from 'select-dom'; From 176c61c3dcd551f48366f399a7daa59b85cc511b Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 12:26:59 +0530 Subject: [PATCH 25/54] Rename to 'tag-changelog-link' --- source/content.ts | 2 +- source/features/tag-changelog-link.css | 14 ++++++++++++++ ...previous-release.tsx => tag-changelog-link.tsx} | 8 ++++---- .../what-changed-since-previous-release.css | 14 -------------- 4 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 source/features/tag-changelog-link.css rename source/features/{what-changed-since-previous-release.tsx => tag-changelog-link.tsx} (94%) delete mode 100644 source/features/what-changed-since-previous-release.css diff --git a/source/content.ts b/source/content.ts index cd48d152d48..215c31e0dd3 100644 --- a/source/content.ts +++ b/source/content.ts @@ -98,7 +98,7 @@ import './features/tags-dropdown'; import './features/filter-pr-by-build-status'; import './features/edit-files-faster'; import './features/hide-disabled-milestone-sorter'; -import './features/what-changed-since-previous-release'; +import './features/tag-changelog-link'; import './features/scrollable-code-and-blockquote.css'; import './features/center-reactions-popup.css'; diff --git a/source/features/tag-changelog-link.css b/source/features/tag-changelog-link.css new file mode 100644 index 00000000000..24654d29dda --- /dev/null +++ b/source/features/tag-changelog-link.css @@ -0,0 +1,14 @@ +.commit > ul > li.rgh-tag-changelog-link { + display: inline-block; + margin-top: 4px; + margin-right: 8px; +} + +.release > div:first-child > ul > li.rgh-tag-changelog-link { + margin-bottom: 4px; +} + +.rgh-tag-changelog-link { + cursor: pointer; + font-size: 12px; +} diff --git a/source/features/what-changed-since-previous-release.tsx b/source/features/tag-changelog-link.tsx similarity index 94% rename from source/features/what-changed-since-previous-release.tsx rename to source/features/tag-changelog-link.tsx index 79e7d652e77..a517a4fcaba 100644 --- a/source/features/what-changed-since-previous-release.tsx +++ b/source/features/tag-changelog-link.tsx @@ -5,7 +5,7 @@ get the previous release of the same namespaced tag. See it in action at: https://github.com/parcel-bundler/parcel/releases */ -import './what-changed-since-previous-release.css'; +import './tag-changelog-link.css'; import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; @@ -93,16 +93,16 @@ const getTagComparisonLink = (prevTag: string, nextTag: string): HTMLElement => const {ownerName, repoName} = getOwnerAndRepo(); return ( -
  • +
  • -
    {diff()}
    compare + {diff()} Changelog
  • ); }; features.add({ - id: 'what-changed-since-previous-release', + id: 'tag-changelog-link', include: [ features.isReleasesOrTags ], diff --git a/source/features/what-changed-since-previous-release.css b/source/features/what-changed-since-previous-release.css deleted file mode 100644 index 4287b690223..00000000000 --- a/source/features/what-changed-since-previous-release.css +++ /dev/null @@ -1,14 +0,0 @@ -.commit > ul > li.rgh-what-changed { - display: inline-block; - margin-top: 4px; - margin-right: 8px; -} - -.release > div:first-child > ul > li.rgh-what-changed { - margin-bottom: 4px; -} - -.rgh-what-changed { - cursor: pointer; - font-size: 12px; -} From 055d5c44f7ac052752be3ffa88bcc3b106b96ae8 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 13:01:42 +0530 Subject: [PATCH 26/54] Get rid of css file and use GitHub's defined CSS classes --- source/features/tag-changelog-link.css | 14 -------------- source/features/tag-changelog-link.tsx | 4 ++-- 2 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 source/features/tag-changelog-link.css diff --git a/source/features/tag-changelog-link.css b/source/features/tag-changelog-link.css deleted file mode 100644 index 24654d29dda..00000000000 --- a/source/features/tag-changelog-link.css +++ /dev/null @@ -1,14 +0,0 @@ -.commit > ul > li.rgh-tag-changelog-link { - display: inline-block; - margin-top: 4px; - margin-right: 8px; -} - -.release > div:first-child > ul > li.rgh-tag-changelog-link { - margin-bottom: 4px; -} - -.rgh-tag-changelog-link { - cursor: pointer; - font-size: 12px; -} diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index a517a4fcaba..95b91a34cd5 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -5,7 +5,7 @@ get the previous release of the same namespaced tag. See it in action at: https://github.com/parcel-bundler/parcel/releases */ -import './tag-changelog-link.css'; + import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; @@ -93,7 +93,7 @@ const getTagComparisonLink = (prevTag: string, nextTag: string): HTMLElement => const {ownerName, repoName} = getOwnerAndRepo(); return ( -
  • +
  • {diff()} Changelog From f8ca2a351bc0b32c9af84b29709ecb92d127c5c3 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 13:07:57 +0530 Subject: [PATCH 27/54] Inline JSX --- source/features/tag-changelog-link.tsx | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 95b91a34cd5..bce0b047cc6 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -40,11 +40,19 @@ async function init(): Promise { allCommitIds.push(...extractValuesFromPathname(select.all(commitIdSelector, nextPage), commitRegExp)); } + const {ownerName, repoName} = getOwnerAndRepo(); + for (let index = 0; index < allCommitIdsAnchor.length; index++) { const previousTagIndex = getPreviousTagIndex(index, allCommitIds, allTags); if (previousTagIndex !== -1) { - allCommitIdsAnchor[index].closest('ul')!.append(getTagComparisonLink(allTags[previousTagIndex], allTags[index])); + allCommitIdsAnchor[index].closest('ul')!.append( +
  • + + {diff()} Changelog + +
  • + ); } } } @@ -87,19 +95,8 @@ const getPreviousTagIndex = (index: number, allCommitIds: string[], allTags: str return prevTagIndex; }; -const doesNamespaceMatch = (tag1: string, tag2: string): boolean => tag1.split(/@[^@]+$/)[0] === tag2.split(/@[^@]+$/)[0]; - -const getTagComparisonLink = (prevTag: string, nextTag: string): HTMLElement => { - const {ownerName, repoName} = getOwnerAndRepo(); - - return ( -
  • - - {diff()} Changelog - -
  • - ); -}; +const doesNamespaceMatch = (tag1: string, tag2: string): boolean => + tag1.split(/@[^@]+$/)[0] === tag2.split(/@[^@]+$/)[0]; features.add({ id: 'tag-changelog-link', From 41a53f22772fad4974aa691a39098c9a4eeac98d Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 13:19:02 +0530 Subject: [PATCH 28/54] Add tooltip --- source/features/tag-changelog-link.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index bce0b047cc6..d054f016b6d 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -43,12 +43,16 @@ async function init(): Promise { const {ownerName, repoName} = getOwnerAndRepo(); for (let index = 0; index < allCommitIdsAnchor.length; index++) { - const previousTagIndex = getPreviousTagIndex(index, allCommitIds, allTags); + const prevTagIndex = getPreviousTagIndex(index, allCommitIds, allTags); - if (previousTagIndex !== -1) { + if (prevTagIndex !== -1) { allCommitIdsAnchor[index].closest('ul')!.append(
  • - + {diff()} Changelog
  • From fb88b25969b3e7d649297ff2e09fbbfe7f13a89b Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Wed, 1 May 2019 13:37:49 +0530 Subject: [PATCH 29/54] Fix issue on Firefox https://github.com/sindresorhus/refined-github/pull/1998#issuecomment-488231253 Co-Authored-By: HardikModha --- source/features/tag-changelog-link.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index d054f016b6d..c0cde79b81e 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -76,7 +76,7 @@ const getNextPageForSinglePageTag = async (tag: string): Promise { From 088d5f1628b657966802ea1b84a7f34f4fbea981 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 13:48:39 +0530 Subject: [PATCH 30/54] Regex not needed to extract commit id and tag --- source/features/tag-changelog-link.tsx | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index c0cde79b81e..e946bfd0bbe 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -19,25 +19,19 @@ async function init(): Promise { return false; } - // To extract the tag "v16.8.6" from links like "/facebook/react/releases/tag/v16.8.6" - const tagRegExp = /releases\/tag\/(.*)$/; - - // To extract the commit hash from links like "/facebook/react/commit/92a1d8feac32d03ab5ea6ac13ae4941f6ae93b54" - const commitRegExp = /commit\/([0-9a-f]{40})$/; - const tagSelector = 'h4.commit-title a[href*="/releases/tag"], .commit .release-header a[href*="/releases/tag"]'; const commitIdSelector = '.commit > ul a[href*="/commit/"], .release > div:first-child > ul a[href*="/commit/"]'; - const allTags = extractValuesFromPathname(select.all(tagSelector), tagRegExp); + const allTags = extractTextFromAnchors(select.all(tagSelector)); const allCommitIdsAnchor = select.all(commitIdSelector); - const allCommitIds = extractValuesFromPathname(allCommitIdsAnchor, commitRegExp); + const allCommitIds = extractTextFromAnchors(allCommitIdsAnchor); const nextPageLink = select('.pagination a:last-child'); const nextPage = nextPageLink ? await fetchDom(nextPageLink.href) : await getNextPageForSinglePageTag(allTags[0]); if (nextPage) { - allTags.push(...extractValuesFromPathname(select.all(tagSelector, nextPage), tagRegExp)); - allCommitIds.push(...extractValuesFromPathname(select.all(commitIdSelector, nextPage), commitRegExp)); + allTags.push(...extractTextFromAnchors(select.all(tagSelector, nextPage))); + allCommitIds.push(...extractTextFromAnchors(select.all(commitIdSelector, nextPage))); } const {ownerName, repoName} = getOwnerAndRepo(); @@ -61,13 +55,8 @@ async function init(): Promise { } } -const extractValuesFromPathname = (anchors: HTMLAnchorElement[], regexp: RegExp): string[] => { - return anchors.map((anchor: HTMLAnchorElement): string => { - const [, value] = anchor.pathname.match(regexp)!; - - return decodeURIComponent(value); - }); -}; +const extractTextFromAnchors = (anchors: HTMLAnchorElement[]): string[] => + anchors.map((anchor: HTMLAnchorElement): string => anchor.textContent!.trim()); const getNextPageForSinglePageTag = async (tag: string): Promise => { if (!isSingleTagPage()) { From 6b2c871a68d26d16426e87dcd6ce2f8507528f13 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Wed, 1 May 2019 13:55:01 +0530 Subject: [PATCH 31/54] Add comment explaining the reason for location.origin --- source/features/tag-changelog-link.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index e946bfd0bbe..82b5aa850e3 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -65,6 +65,8 @@ const getNextPageForSinglePageTag = async (tag: string): Promise Date: Wed, 1 May 2019 13:55:01 +0530 Subject: [PATCH 32/54] Add comment explaining the reason for location.origin --- source/features/tag-changelog-link.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 82b5aa850e3..ed904a196a2 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -65,7 +65,7 @@ const getNextPageForSinglePageTag = async (tag: string): Promise Date: Thu, 2 May 2019 14:14:39 +0800 Subject: [PATCH 33/54] Query once; merge functions; avoid indexes when possible --- source/features/tag-changelog-link.tsx | 88 +++++++++++--------------- 1 file changed, 37 insertions(+), 51 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index ed904a196a2..d39060e00d9 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -1,4 +1,4 @@ -/** +/* This feature adds a compare link on each releases/tags/single tag page so that you can see what has changed since the previous release. If the tags are namespaced then it tries to get the previous release of the same namespaced tag. @@ -10,42 +10,45 @@ import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; -import {getOwnerAndRepo} from '../libs/utils'; -import {isSingleTagPage} from '../libs/page-detect'; import {diff} from '../libs/icons'; +import {isSingleTagPage} from '../libs/page-detect'; +import {getRepoPath, getRepoURL} from '../libs/utils'; -async function init(): Promise { - if (select.exists('.blankslate')) { - return false; +async function getNextPage(): Promise { + const nextPageLink = select('.pagination a:last-child'); + if (nextPageLink) { + return fetchDom(nextPageLink.href); } - const tagSelector = 'h4.commit-title a[href*="/releases/tag"], .commit .release-header a[href*="/releases/tag"]'; - const commitIdSelector = '.commit > ul a[href*="/commit/"], .release > div:first-child > ul a[href*="/commit/"]'; - - const allTags = extractTextFromAnchors(select.all(tagSelector)); - const allCommitIdsAnchor = select.all(commitIdSelector); - const allCommitIds = extractTextFromAnchors(allCommitIdsAnchor); + if (isSingleTagPage()) { + const [, tag = ''] = getRepoPath()!.split('releases/tag/', 2); // Already URL-encoded + return fetchDom(`/${getRepoURL()}/tags?after=${tag}`); + } - const nextPageLink = select('.pagination a:last-child'); - const nextPage = nextPageLink ? await fetchDom(nextPageLink.href) : await getNextPageForSinglePageTag(allTags[0]); + return new DocumentFragment(); +} - if (nextPage) { - allTags.push(...extractTextFromAnchors(select.all(tagSelector, nextPage))); - allCommitIds.push(...extractTextFromAnchors(select.all(commitIdSelector, nextPage))); +async function init(): Promise { + if (select.exists('.blankslate')) { + return false; } - const {ownerName, repoName} = getOwnerAndRepo(); + const documents = [document, await getNextPage()] as any; // TODO: fix select-dom types to accept mixed arrays + const tagElements = select.all('[href*="/releases/tag"]', documents); + const commitElements = select.all('.muted-link[href*="/commit/"]', documents); + const tags = tagElements.map(anchor => anchor.textContent!.trim()); + const commits = commitElements.map(anchor => anchor.textContent!.trim()); - for (let index = 0; index < allCommitIdsAnchor.length; index++) { - const prevTagIndex = getPreviousTagIndex(index, allCommitIds, allTags); + for (const [index, commitElement] of commitElements.entries()) { + const previousTag = getPreviousTag(index, commits, tags); - if (prevTagIndex !== -1) { - allCommitIdsAnchor[index].closest('ul')!.append( + if (previousTag !== false) { + commitElement.closest('ul')!.append(
  • {diff()} Changelog @@ -55,44 +58,27 @@ async function init(): Promise { } } -const extractTextFromAnchors = (anchors: HTMLAnchorElement[]): string[] => - anchors.map((anchor: HTMLAnchorElement): string => anchor.textContent!.trim()); - -const getNextPageForSinglePageTag = async (tag: string): Promise => { - if (!isSingleTagPage()) { - return; - } - - const {ownerName, repoName} = getOwnerAndRepo(); - - // Firefox requires location.origin for fetch without that relative URLs will fail on Firefox. - // See: https://github.com/sindresorhus/refined-github/pull/1998#issuecomment-488231253 - return fetchDom(`${location.origin}/${ownerName}/${repoName}/releases?after=${tag}`); -}; +const getPreviousTag = (index: number, commits: string[], tags: string[]): string | false => { + let previousTag: string | false = false; -const getPreviousTagIndex = (index: number, allCommitIds: string[], allTags: string[]): number => { - let prevTagIndex = -1; - - for (let i = index + 1; i < allCommitIds.length; i++) { - if (allCommitIds[i] === allCommitIds[index]) { + for (let i = index + 1; i < commits.length; i++) { + if (commits[i] === commits[index]) { continue; } - if (doesNamespaceMatch(allTags[i], allTags[index])) { - return i; + // Ensure that they have the same namespace. e.g. `parcel@1.2.4` and `parcel@1.2.3` + if (tags[i].split(/@[^@]+$/)[0] === tags[index].split(/@[^@]+$/)[0]) { + return tags[i]; } - if (prevTagIndex === -1) { - prevTagIndex = i; + if (previousTag === false) { + previousTag = tags[i]; } } - return prevTagIndex; + return previousTag; }; -const doesNamespaceMatch = (tag1: string, tag2: string): boolean => - tag1.split(/@[^@]+$/)[0] === tag2.split(/@[^@]+$/)[0]; - features.add({ id: 'tag-changelog-link', include: [ From 228df3ff072c4ee694777409c185a3c8a23532c6 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Thu, 2 May 2019 15:28:26 +0800 Subject: [PATCH 34/54] Fix tag selector --- source/features/tag-changelog-link.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index d39060e00d9..bb5a436642d 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -34,7 +34,11 @@ async function init(): Promise { } const documents = [document, await getNextPage()] as any; // TODO: fix select-dom types to accept mixed arrays - const tagElements = select.all('[href*="/releases/tag"]', documents); + // These selectors need to work on: + // https://github.com/facebook/react/tags (tags list) + // https://github.com/facebook/react/releases (releases list) + // https://github.com/parcel-bundler/parcel/releases (releases list without release notes) + const tagElements = select.all('.f1 [href*="/releases/tag"], .commit-title [href*="/releases/tag"]', documents); const commitElements = select.all('.muted-link[href*="/commit/"]', documents); const tags = tagElements.map(anchor => anchor.textContent!.trim()); const commits = commitElements.map(anchor => anchor.textContent!.trim()); From 29aae2834a31c3c0cb8ca1af63ca9049640dbd7d Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Thu, 2 May 2019 15:28:59 +0800 Subject: [PATCH 35/54] Avoid jumps caused by margins --- source/features/tag-changelog-link.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index bb5a436642d..61914c1c7d1 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -47,10 +47,11 @@ async function init(): Promise { const previousTag = getPreviousTag(index, commits, tags); if (previousTag !== false) { - commitElement.closest('ul')!.append( -
  • + const container = commitElement.closest('ul')!; + container.append( +
  • @@ -64,7 +65,6 @@ async function init(): Promise { const getPreviousTag = (index: number, commits: string[], tags: string[]): string | false => { let previousTag: string | false = false; - for (let i = index + 1; i < commits.length; i++) { if (commits[i] === commits[index]) { continue; From dbfe9bb99dacc0676a3703764defd25f5cb90d5f Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Thu, 2 May 2019 23:25:52 +0530 Subject: [PATCH 36/54] Add feature screenshot in readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 58619d5e8ed..1c9dc5cb14b 100644 --- a/readme.md +++ b/readme.md @@ -202,6 +202,7 @@ GitHub Enterprise is also supported. More info in the options. - [Follow file renames in commits lists.](https://user-images.githubusercontent.com/1402241/54799957-7306a280-4c9a-11e9-86de-b9764ed93397.png) - [Edit files straight from a repo’s list by clicking their icon.](https://user-images.githubusercontent.com/1402241/56370462-d51cde00-622d-11e9-8cd3-8a173bd3dc08.png) - [Search or select tags from a dropdown in the `Releases` page.](https://user-images.githubusercontent.com/22439276/56373231-27ee9980-621e-11e9-9b21-601919d3dddf.png) +- [See what has changed since the previous release](https://user-images.githubusercontent.com/1402241/57081611-ad4a7180-6d27-11e9-9cb6-c54ec1ac18bb.png) ### Previously part of Refined GitHub From 67822230c90af73e2d4459d680028d53b82e4d05 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Fri, 3 May 2019 00:39:34 +0530 Subject: [PATCH 37/54] Fix the commit id selector to avoid false matches --- source/features/tag-changelog-link.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 61914c1c7d1..09e0af82302 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -39,7 +39,7 @@ async function init(): Promise { // https://github.com/facebook/react/releases (releases list) // https://github.com/parcel-bundler/parcel/releases (releases list without release notes) const tagElements = select.all('.f1 [href*="/releases/tag"], .commit-title [href*="/releases/tag"]', documents); - const commitElements = select.all('.muted-link[href*="/commit/"]', documents); + const commitElements = select.all('.commit > ul a[href*="/commit/"], .release > div:first-child > ul a[href*="/commit/"]', documents); const tags = tagElements.map(anchor => anchor.textContent!.trim()); const commits = commitElements.map(anchor => anchor.textContent!.trim()); From b50f7b3bfd1376a8dd898860f3aa288a33c1d2e1 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 5 May 2019 05:22:45 +0530 Subject: [PATCH 38/54] Fixes to make it work with custom tag names. 1. Now extracting tag name from the tag link rather than from anchor textContent. Fixes https://github.com/sindresorhus/refined-github/pull/1998#issuecomment-488953838 2. Querying subparts of the document for tag/commit hash. 3. Adding the Changelog link to all the subdocuments to the feature on smaller windows. Fixes https://github.com/sindresorhus/refined-github/pull/1998#issuecomment-488970348 --- source/features/tag-changelog-link.tsx | 51 ++++++++++++++++---------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 09e0af82302..395c58c291e 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -1,7 +1,6 @@ /* -This feature adds a compare link on each releases/tags/single tag page so that you can see -what has changed since the previous release. If the tags are namespaced then it tries to -get the previous release of the same namespaced tag. +Adds a compare link on each releases/tags/single tag page so that you can see what has changed since the previous release. +If the tags are namespaced then it tries to get the previous release of the same namespaced tag. See it in action at: https://github.com/parcel-bundler/parcel/releases */ @@ -33,45 +32,57 @@ async function init(): Promise { return false; } + const tagRegex = /\/releases\/tag\/(.*)/; + const documents = [document, await getNextPage()] as any; // TODO: fix select-dom types to accept mixed arrays + const tagContainers = select.all('.release, .Box-row .commit, .release-entry .release-main-section:not(.commit)', documents); + // These selectors need to work on: // https://github.com/facebook/react/tags (tags list) // https://github.com/facebook/react/releases (releases list) // https://github.com/parcel-bundler/parcel/releases (releases list without release notes) - const tagElements = select.all('.f1 [href*="/releases/tag"], .commit-title [href*="/releases/tag"]', documents); - const commitElements = select.all('.commit > ul a[href*="/commit/"], .release > div:first-child > ul a[href*="/commit/"]', documents); - const tags = tagElements.map(anchor => anchor.textContent!.trim()); + const tagElements = select.all('h4.commit-title > a[href*="/releases/tag/"], div.release-header .f1 > a[href*="/releases/tag/"]', tagContainers); + const commitElements = select.all('div.release-header ul a[href*="/commit/"].muted-link, .commit ul a[href*="/commit/"].muted-link', tagContainers); + + const tags = tagElements.map(anchor => decodeURIComponent(anchor.pathname.match(tagRegex)![1])); const commits = commitElements.map(anchor => anchor.textContent!.trim()); - for (const [index, commitElement] of commitElements.entries()) { + for (const [index, tagContainer] of tagContainers.entries()) { const previousTag = getPreviousTag(index, commits, tags); if (previousTag !== false) { - const container = commitElement.closest('ul')!; - container.append( -
  • - - {diff()} Changelog - -
  • - ); + const unorderedLists = tagContainer.querySelectorAll('.commit > ul.f6, .commit > .release-header > ul, div:first-child > ul'); + + for (const list of unorderedLists) { + list.append( +
  • + + {diff()} Changelog + +
  • + ); + } } } } const getPreviousTag = (index: number, commits: string[], tags: string[]): string | false => { let previousTag: string | false = false; + + // If tag is `@parcel/integration-tests@1.12.2` then namespace is `@parcel/integration-tests` + const namespaceRegex = /@[^@]+$/; + for (let i = index + 1; i < commits.length; i++) { if (commits[i] === commits[index]) { continue; } // Ensure that they have the same namespace. e.g. `parcel@1.2.4` and `parcel@1.2.3` - if (tags[i].split(/@[^@]+$/)[0] === tags[index].split(/@[^@]+$/)[0]) { + if (tags[i].split(namespaceRegex)[0] === tags[index].split(namespaceRegex)[0]) { return tags[i]; } From 758132bdbafc5c7b1881b1c0bdafbf216c5675d9 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 5 May 2019 05:35:08 +0530 Subject: [PATCH 39/54] Remove flex-grow on smaller windows and add myself as CODEOWNER --- .github/CODEOWNERS | 1 + source/features/tag-changelog-link.css | 3 +++ source/features/tag-changelog-link.tsx | 3 +-- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 source/features/tag-changelog-link.css diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 48db1a33c09..64e988511cc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,3 @@ source/features/filter-pr-by-build-status.tsx @HardikModha source/features/tags-dropdown.tsx @HardikModha +source/features/tag-changelog-link.tsx @HardikModha diff --git a/source/features/tag-changelog-link.css b/source/features/tag-changelog-link.css new file mode 100644 index 00000000000..576841bbea6 --- /dev/null +++ b/source/features/tag-changelog-link.css @@ -0,0 +1,3 @@ +.release div.release-header > ul > li { + flex-grow: 0 !important; +} diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 395c58c291e..2644392760e 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -4,7 +4,7 @@ If the tags are namespaced then it tries to get the previous release of the same See it in action at: https://github.com/parcel-bundler/parcel/releases */ - +import './tag-changelog-link.css'; import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; @@ -33,7 +33,6 @@ async function init(): Promise { } const tagRegex = /\/releases\/tag\/(.*)/; - const documents = [document, await getNextPage()] as any; // TODO: fix select-dom types to accept mixed arrays const tagContainers = select.all('.release, .Box-row .commit, .release-entry .release-main-section:not(.commit)', documents); From 0e9f33d67b9e9ffa25e4c807109317e76704b04b Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 5 May 2019 20:12:41 +0530 Subject: [PATCH 40/54] Simplify selectors --- source/features/tag-changelog-link.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 2644392760e..7c0fd2c99a7 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -34,14 +34,14 @@ async function init(): Promise { const tagRegex = /\/releases\/tag\/(.*)/; const documents = [document, await getNextPage()] as any; // TODO: fix select-dom types to accept mixed arrays - const tagContainers = select.all('.release, .Box-row .commit, .release-entry .release-main-section:not(.commit)', documents); + const tagContainers = select.all('.release, .Box-row .commit, .release-main-section:not(.commit)', documents); // These selectors need to work on: // https://github.com/facebook/react/tags (tags list) // https://github.com/facebook/react/releases (releases list) // https://github.com/parcel-bundler/parcel/releases (releases list without release notes) const tagElements = select.all('h4.commit-title > a[href*="/releases/tag/"], div.release-header .f1 > a[href*="/releases/tag/"]', tagContainers); - const commitElements = select.all('div.release-header ul a[href*="/commit/"].muted-link, .commit ul a[href*="/commit/"].muted-link', tagContainers); + const commitElements = select.all('.commit ul a[href*="/commit/"].muted-link', tagContainers); const tags = tagElements.map(anchor => decodeURIComponent(anchor.pathname.match(tagRegex)![1])); const commits = commitElements.map(anchor => anchor.textContent!.trim()); From c5f4f5a192c4cd400d3b2460b25b61be9aa830da Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 5 May 2019 20:51:12 +0530 Subject: [PATCH 41/54] Use select.all --- source/features/tag-changelog-link.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 7c0fd2c99a7..2c873d96bcd 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -50,7 +50,7 @@ async function init(): Promise { const previousTag = getPreviousTag(index, commits, tags); if (previousTag !== false) { - const unorderedLists = tagContainer.querySelectorAll('.commit > ul.f6, .commit > .release-header > ul, div:first-child > ul'); + const unorderedLists = select.all('.commit > ul.f6, .commit > .release-header > ul, div:first-child > ul', tagContainer); for (const list of unorderedLists) { list.append( From 5c0d57f11aabffde2c4b611dc4205538f5cfba18 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 5 May 2019 21:31:40 +0530 Subject: [PATCH 42/54] Handled an edge case There can be tags which are collapsed under a placeholder tag container. This placeholder container also contain the same selector but does not contain an actual tag and commit hash. To avoid selection of such tags an extra selector is added. See https://github.com/facebook/react/releases?after=v16.7.0 for an example for this edge case. You will see the text "Show two newer tags" --- source/features/tag-changelog-link.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 2c873d96bcd..302bc842509 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -34,7 +34,10 @@ async function init(): Promise { const tagRegex = /\/releases\/tag\/(.*)/; const documents = [document, await getNextPage()] as any; // TODO: fix select-dom types to accept mixed arrays - const tagContainers = select.all('.release, .Box-row .commit, .release-main-section:not(.commit)', documents); + + // not(.js-timeline-tags-expander) is needed as there can be some tags collapsed + // See https://github.com/facebook/react/releases?after=v16.7.0 for an example + const tagContainers = select.all('.release, .Box-row .commit, .release-main-section:not(.commit):not(.js-timeline-tags-expander)', documents); // These selectors need to work on: // https://github.com/facebook/react/tags (tags list) From 3e77c4ca87df50d53c5228f0ba42e80022e118fd Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Sun, 5 May 2019 22:13:11 +0530 Subject: [PATCH 43/54] Use suggested approach as we need to iterate only once to fetch tag and commit details --- source/features/tag-changelog-link.tsx | 40 +++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 302bc842509..70fc32f4b0a 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -13,6 +13,12 @@ import {diff} from '../libs/icons'; import {isSingleTagPage} from '../libs/page-detect'; import {getRepoPath, getRepoURL} from '../libs/utils'; +type TagDetails = { + element: HTMLElement; + commit: string; + tag: string; +} + async function getNextPage(): Promise { const nextPageLink = select('.pagination a:last-child'); if (nextPageLink) { @@ -35,25 +41,27 @@ async function init(): Promise { const tagRegex = /\/releases\/tag\/(.*)/; const documents = [document, await getNextPage()] as any; // TODO: fix select-dom types to accept mixed arrays - // not(.js-timeline-tags-expander) is needed as there can be some tags collapsed + // not(.js-timeline-tags-expander) is needed as there can be some collapsed tags // See https://github.com/facebook/react/releases?after=v16.7.0 for an example - const tagContainers = select.all('.release, .Box-row .commit, .release-main-section:not(.commit):not(.js-timeline-tags-expander)', documents); + const tagContainerSelector = '.release, .Box-row .commit, .release-entry .release-main-section:not(.commit):not(.js-timeline-tags-expander)'; // These selectors need to work on: // https://github.com/facebook/react/tags (tags list) // https://github.com/facebook/react/releases (releases list) // https://github.com/parcel-bundler/parcel/releases (releases list without release notes) - const tagElements = select.all('h4.commit-title > a[href*="/releases/tag/"], div.release-header .f1 > a[href*="/releases/tag/"]', tagContainers); - const commitElements = select.all('.commit ul a[href*="/commit/"].muted-link', tagContainers); + const tagSelector = 'h4.commit-title > a[href*="/releases/tag/"], div.release-header .f1 > a[href*="/releases/tag/"]'; - const tags = tagElements.map(anchor => decodeURIComponent(anchor.pathname.match(tagRegex)![1])); - const commits = commitElements.map(anchor => anchor.textContent!.trim()); + const allTags: TagDetails[] = select.all(tagContainerSelector, documents).map(element => ({ + element, + tag: decodeURIComponent(select(tagSelector, element)!.pathname.match(tagRegex)![1]), + commit: select('.commit ul a[href*="/commit/"].muted-link', element)!.textContent!.trim() + })); - for (const [index, tagContainer] of tagContainers.entries()) { - const previousTag = getPreviousTag(index, commits, tags); + for (const [index, container] of allTags.entries()) { + const previousTag = getPreviousTag(index, allTags); if (previousTag !== false) { - const unorderedLists = select.all('.commit > ul.f6, .commit > .release-header > ul, div:first-child > ul', tagContainer); + const unorderedLists = select.all('.commit > ul.f6, .commit > .release-header > ul, div:first-child > ul', container.element); for (const list of unorderedLists) { list.append( @@ -61,7 +69,7 @@ async function init(): Promise { {diff()} Changelog @@ -72,24 +80,24 @@ async function init(): Promise { } } -const getPreviousTag = (index: number, commits: string[], tags: string[]): string | false => { +const getPreviousTag = (index: number, allTags: TagDetails[]): string | false => { let previousTag: string | false = false; // If tag is `@parcel/integration-tests@1.12.2` then namespace is `@parcel/integration-tests` const namespaceRegex = /@[^@]+$/; - for (let i = index + 1; i < commits.length; i++) { - if (commits[i] === commits[index]) { + for (let i = index + 1; i < allTags.length; i++) { + if (allTags[i].commit === allTags[index].commit) { continue; } // Ensure that they have the same namespace. e.g. `parcel@1.2.4` and `parcel@1.2.3` - if (tags[i].split(namespaceRegex)[0] === tags[index].split(namespaceRegex)[0]) { - return tags[i]; + if (allTags[i].tag.split(namespaceRegex)[0] === allTags[index].tag.split(namespaceRegex)[0]) { + return allTags[i].tag; } if (previousTag === false) { - previousTag = tags[i]; + previousTag = allTags[i].tag; } } From 7ef21c2f459c6cc412fc6e4ba5181885abf99736 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 6 May 2019 00:10:37 +0530 Subject: [PATCH 44/54] Move namespace extraction to a method and simplify selectors --- source/features/tag-changelog-link.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 70fc32f4b0a..3112942e190 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -49,12 +49,11 @@ async function init(): Promise { // https://github.com/facebook/react/tags (tags list) // https://github.com/facebook/react/releases (releases list) // https://github.com/parcel-bundler/parcel/releases (releases list without release notes) - const tagSelector = 'h4.commit-title > a[href*="/releases/tag/"], div.release-header .f1 > a[href*="/releases/tag/"]'; const allTags: TagDetails[] = select.all(tagContainerSelector, documents).map(element => ({ element, - tag: decodeURIComponent(select(tagSelector, element)!.pathname.match(tagRegex)![1]), - commit: select('.commit ul a[href*="/commit/"].muted-link', element)!.textContent!.trim() + tag: decodeURIComponent(select('[href*="/releases/tag/"]', element)!.pathname.match(tagRegex)![1]), + commit: select('[href*="/commit/"]', element)!.textContent!.trim() })); for (const [index, container] of allTags.entries()) { @@ -80,19 +79,19 @@ async function init(): Promise { } } +// If tag is `@parcel/integration-tests@1.12.2` then namespace is `@parcel/integration-tests` +const getNameSpace = (tag: string) => tag.split(/@[^@]+$/)[0]; + const getPreviousTag = (index: number, allTags: TagDetails[]): string | false => { let previousTag: string | false = false; - // If tag is `@parcel/integration-tests@1.12.2` then namespace is `@parcel/integration-tests` - const namespaceRegex = /@[^@]+$/; - for (let i = index + 1; i < allTags.length; i++) { if (allTags[i].commit === allTags[index].commit) { continue; } // Ensure that they have the same namespace. e.g. `parcel@1.2.4` and `parcel@1.2.3` - if (allTags[i].tag.split(namespaceRegex)[0] === allTags[index].tag.split(namespaceRegex)[0]) { + if (getNameSpace(allTags[i].tag) === getNameSpace(allTags[index].tag)) { return allTags[i].tag; } From 101021d65021e41712be5efc97fc80a569bff4b3 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 6 May 2019 00:18:15 +0530 Subject: [PATCH 45/54] Lint --- source/features/tag-changelog-link.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 3112942e190..5ecdb192e8f 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -80,7 +80,7 @@ async function init(): Promise { } // If tag is `@parcel/integration-tests@1.12.2` then namespace is `@parcel/integration-tests` -const getNameSpace = (tag: string) => tag.split(/@[^@]+$/)[0]; +const getNameSpace = (tag: string): string => tag.split(/@[^@]+$/)[0]; const getPreviousTag = (index: number, allTags: TagDetails[]): string | false => { let previousTag: string | false = false; From 89d649bd55e79cc1f88d3760818f5b97eccc6114 Mon Sep 17 00:00:00 2001 From: Hardik Modha Date: Mon, 6 May 2019 00:34:00 +0530 Subject: [PATCH 46/54] Move decodeURIComponent to tooltip text --- source/features/tag-changelog-link.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 5ecdb192e8f..e9cd2bb2c54 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -52,7 +52,7 @@ async function init(): Promise { const allTags: TagDetails[] = select.all(tagContainerSelector, documents).map(element => ({ element, - tag: decodeURIComponent(select('[href*="/releases/tag/"]', element)!.pathname.match(tagRegex)![1]), + tag: select('[href*="/releases/tag/"]', element)!.pathname.match(tagRegex)![1], commit: select('[href*="/commit/"]', element)!.textContent!.trim() })); @@ -67,7 +67,7 @@ async function init(): Promise {
  • {diff()} Changelog From c217b2920ed4b4865528186dde208ce4439d79ef Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 10 May 2019 13:22:00 +0800 Subject: [PATCH 47/54] Update select-dom to fix types --- package-lock.json | 47 ++++++++++++++++++-------- package.json | 2 +- source/features/tag-changelog-link.tsx | 2 +- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 96a0ef33aa2..9572146ad9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5935,7 +5935,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -5956,12 +5957,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5976,17 +5979,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -6103,7 +6109,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -6115,6 +6122,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6129,6 +6137,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6136,12 +6145,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6160,6 +6171,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -6240,7 +6252,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -6252,6 +6265,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -6337,7 +6351,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -6373,6 +6388,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6392,6 +6408,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6435,12 +6452,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -10790,9 +10809,9 @@ } }, "select-dom": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/select-dom/-/select-dom-5.0.1.tgz", - "integrity": "sha512-cpNrVqu6spg6B7bA5J8latFzHOXWh2UWYrVheemrnEfJQduUXmoVZZtgRiWTOe/axNoWsRODJ1otgy2f7Vol7g==" + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/select-dom/-/select-dom-5.0.2.tgz", + "integrity": "sha512-j0kx0KeZLPBL6hDF8FNy55lLPNnduxeFaLPJVDHVLpwbjv4syoZnoGe7MoFa5qzwVtNYlRr5B0rRGNvV1R4Mww==" }, "semver": { "version": "5.7.0", diff --git a/package.json b/package.json index 868ac53c955..52146fb6946 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "linkify-urls": "^2.2.0", "onetime": "^5.0.0", "p-memoize": "^3.0.0", - "select-dom": "^5.0.1", + "select-dom": "^5.0.2", "shorten-repo-url": "^1.5.1", "tiny-version-compare": "^1.0.0", "type-fest": "^0.4.1", diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index e9cd2bb2c54..4a4f178e4d3 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -39,7 +39,7 @@ async function init(): Promise { } const tagRegex = /\/releases\/tag\/(.*)/; - const documents = [document, await getNextPage()] as any; // TODO: fix select-dom types to accept mixed arrays + const documents = [document, await getNextPage()]; // not(.js-timeline-tags-expander) is needed as there can be some collapsed tags // See https://github.com/facebook/react/releases?after=v16.7.0 for an example From ceb26cd09503542778d4c638f13a84dd0954a0c0 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 10 May 2019 13:27:50 +0800 Subject: [PATCH 48/54] Shorten selectors and update+merge comments `.release-main-section .commit` works on tags in releases list, whether open or collapsed, avoiding the "dummy release" uncollapser element because that doesn't include a `.commit` element. Tested on https://github.com/facebook/react/releases?after=v16.7.0 --- source/features/tag-changelog-link.tsx | 33 +++++++++++++++----------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 4a4f178e4d3..944e33c3854 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -33,28 +33,33 @@ async function getNextPage(): Promise { return new DocumentFragment(); } +function parseTags(element: HTMLElement): TagDetails { + return { + element, + commit: select('[href*="/commit/"]', element)!.textContent!.trim(), + tag: select('[href*="/releases/tag/"]', element)!.pathname.match(/\/releases\/tag\/(.*)/)![1] + }; +} + async function init(): Promise { if (select.exists('.blankslate')) { return false; } - const tagRegex = /\/releases\/tag\/(.*)/; - const documents = [document, await getNextPage()]; + const tagsSelectors = [ + // https://github.com/facebook/react/releases (release in releases list) + '.release', - // not(.js-timeline-tags-expander) is needed as there can be some collapsed tags - // See https://github.com/facebook/react/releases?after=v16.7.0 for an example - const tagContainerSelector = '.release, .Box-row .commit, .release-entry .release-main-section:not(.commit):not(.js-timeline-tags-expander)'; + // https://github.com/facebook/react/releases?after=v16.7.0 (tags in releases list) + '.release-main-section .commit', - // These selectors need to work on: - // https://github.com/facebook/react/tags (tags list) - // https://github.com/facebook/react/releases (releases list) - // https://github.com/parcel-bundler/parcel/releases (releases list without release notes) + // https://github.com/facebook/react/tags (tags list) + '.Box-row .commit' + ].join(); - const allTags: TagDetails[] = select.all(tagContainerSelector, documents).map(element => ({ - element, - tag: select('[href*="/releases/tag/"]', element)!.pathname.match(tagRegex)![1], - commit: select('[href*="/commit/"]', element)!.textContent!.trim() - })); + // Look for tags in the current page and the next page + const pages = [document, await getNextPage()]; + const allTags = select.all(tagsSelectors, pages).map(parseTags); for (const [index, container] of allTags.entries()) { const previousTag = getPreviousTag(index, allTags); From 04a95b4a0f7969dfeccf40dc03253b06ba6d8d59 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 10 May 2019 15:06:56 +0800 Subject: [PATCH 49/54] Handle `Verified` label on mobile release pages --- source/features/tag-changelog-link.css | 3 --- source/features/tag-changelog-link.tsx | 15 +++++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 source/features/tag-changelog-link.css diff --git a/source/features/tag-changelog-link.css b/source/features/tag-changelog-link.css deleted file mode 100644 index 576841bbea6..00000000000 --- a/source/features/tag-changelog-link.css +++ /dev/null @@ -1,3 +0,0 @@ -.release div.release-header > ul > li { - flex-grow: 0 !important; -} diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 944e33c3854..26260bdc99c 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -4,7 +4,6 @@ If the tags are namespaced then it tries to get the previous release of the same See it in action at: https://github.com/parcel-bundler/parcel/releases */ -import './tag-changelog-link.css'; import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; @@ -65,11 +64,11 @@ async function init(): Promise { const previousTag = getPreviousTag(index, allTags); if (previousTag !== false) { - const unorderedLists = select.all('.commit > ul.f6, .commit > .release-header > ul, div:first-child > ul', container.element); - - for (const list of unorderedLists) { - list.append( -
  • + // Signed releases include on mobile include a "Verified"
    inside the `ul`. `li:last-of-type` excludes it. + // Example: https://github.com/tensorflow/tensorflow/releases?after=v1.12.0-rc1 + for (const lastLink of select.all('.list-style-none > li:last-of-type', container.element)) { + lastLink.after( +
  • {
  • ); + + // `lastLink` is no longer the last link, so it shouldn't push our new link away. + // Same page as before: https://github.com/tensorflow/tensorflow/releases?after=v1.12.0-rc1 + lastLink.classList.remove('flex-auto'); } } } From 5bbd88d3d0c518a02eb053d4a336813ac658965e Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 10 May 2019 15:07:37 +0800 Subject: [PATCH 50/54] Use `icons.diff()` instead of `diff()` --- source/features/tag-changelog-link.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index 26260bdc99c..b7bd9cbe8ac 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -8,7 +8,7 @@ import React from 'dom-chef'; import select from 'select-dom'; import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; -import {diff} from '../libs/icons'; +import * as icons from '../libs/icons'; import {isSingleTagPage} from '../libs/page-detect'; import {getRepoPath, getRepoURL} from '../libs/utils'; @@ -74,7 +74,7 @@ async function init(): Promise { aria-label={'See changes since ' + decodeURIComponent(previousTag)} href={`/${getRepoURL()}/compare/${previousTag}...${allTags[index].tag}`} > - {diff()} Changelog + {icons.diff()} Changelog
  • ); From 073fb8ecf0ed301ce563b4e5baedb8395aead296 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 10 May 2019 15:34:51 +0800 Subject: [PATCH 51/54] Extract and add tests for tag namespace parser --- source/features/tag-changelog-link.tsx | 15 ++++++++------- source/libs/utils.ts | 5 +++++ test/utils.ts | 22 ++++++++++++++++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index b7bd9cbe8ac..c8cea47f201 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -10,12 +10,14 @@ import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; import * as icons from '../libs/icons'; import {isSingleTagPage} from '../libs/page-detect'; -import {getRepoPath, getRepoURL} from '../libs/utils'; +import {getRepoPath, getRepoURL, parseTag} from '../libs/utils'; type TagDetails = { element: HTMLElement; commit: string; tag: string; + version: string; + namespace: string; } async function getNextPage(): Promise { @@ -33,10 +35,12 @@ async function getNextPage(): Promise { } function parseTags(element: HTMLElement): TagDetails { + const tag = select('[href*="/releases/tag/"]', element)!.pathname.match(/\/releases\/tag\/(.*)/)![1]; return { element, + tag, commit: select('[href*="/commit/"]', element)!.textContent!.trim(), - tag: select('[href*="/releases/tag/"]', element)!.pathname.match(/\/releases\/tag\/(.*)/)![1] + ...parseTag(tag) // `version`, `namespace` }; } @@ -87,9 +91,6 @@ async function init(): Promise { } } -// If tag is `@parcel/integration-tests@1.12.2` then namespace is `@parcel/integration-tests` -const getNameSpace = (tag: string): string => tag.split(/@[^@]+$/)[0]; - const getPreviousTag = (index: number, allTags: TagDetails[]): string | false => { let previousTag: string | false = false; @@ -98,11 +99,11 @@ const getPreviousTag = (index: number, allTags: TagDetails[]): string | false => continue; } - // Ensure that they have the same namespace. e.g. `parcel@1.2.4` and `parcel@1.2.3` - if (getNameSpace(allTags[i].tag) === getNameSpace(allTags[index].tag)) { + if (allTags[index].namespace === allTags[i].namespace) { return allTags[i].tag; } + // If no matching namespace is found, just use the next one if (previousTag === false) { previousTag = allTags[i].tag; } diff --git a/source/libs/utils.ts b/source/libs/utils.ts index a3dea51a226..a7ddf562347 100644 --- a/source/libs/utils.ts +++ b/source/libs/utils.ts @@ -40,6 +40,11 @@ export const getOwnerAndRepo = (): { return {ownerName, repoName}; }; +export const parseTag = (tag: string): {version: string; namespace: string} => { + const [, namespace = '', version = ''] = tag.match(/(?:(.*)@)?([^@]+)/) || []; + return {namespace, version}; +}; + export const groupBy = (iterable: Iterable, grouper: (item: string) => string): Record => { const map: Record = {}; diff --git a/test/utils.ts b/test/utils.ts index 82c347272a4..ec3fe4c5584 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,6 +1,11 @@ import test from 'ava'; import './fixtures/globals'; -import * as utils from '../source/libs/utils'; +import { + getDiscussionNumber, + getOwnerAndRepo, + getRepoPath, + parseTag +} from '../source/libs/utils'; test('getDiscussionNumber', t => { const pairs = new Map([ @@ -71,7 +76,7 @@ test('getDiscussionNumber', t => { ]); for (const [url, result] of pairs) { location.href = url; - t.is(result, utils.getDiscussionNumber()); + t.is(result, getDiscussionNumber()); } }); @@ -121,7 +126,7 @@ test('getRepoPath', t => { for (const [url, result] of pairs) { location.href = url; - t.is(result, utils.getRepoPath()); + t.is(result, getRepoPath()); } }); @@ -143,6 +148,15 @@ test('getOwnerAndRepo', t => { Object.keys(ownerAndRepo).forEach(url => { location.href = url; - t.deepEqual(ownerAndRepo[url], utils.getOwnerAndRepo()); + t.deepEqual(ownerAndRepo[url], getOwnerAndRepo()); }); }); + +test('parseTag', t => { + t.deepEqual(parseTag(''), {namespace: '', version: ''}); + t.deepEqual(parseTag('1.2.3'), {namespace: '', version: '1.2.3'}); + t.deepEqual(parseTag('@1.2.3'), {namespace: '', version: '1.2.3'}); + t.deepEqual(parseTag('hi@1.2.3'), {namespace: 'hi', version: '1.2.3'}); + t.deepEqual(parseTag('hi/you@1.2.3'), {namespace: 'hi/you', version: '1.2.3'}); + t.deepEqual(parseTag('@hi/you@1.2.3'), {namespace: '@hi/you', version: '1.2.3'}); +}); From c4788d2eedfc1cc3e648b89f17292d0264836691 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 10 May 2019 15:36:25 +0800 Subject: [PATCH 52/54] Improve variable names and types --- source/features/tag-changelog-link.tsx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index c8cea47f201..eaf0add9f7f 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -67,7 +67,7 @@ async function init(): Promise { for (const [index, container] of allTags.entries()) { const previousTag = getPreviousTag(index, allTags); - if (previousTag !== false) { + if (previousTag) { // Signed releases include on mobile include a "Verified"
    inside the `ul`. `li:last-of-type` excludes it. // Example: https://github.com/tensorflow/tensorflow/releases?after=v1.12.0-rc1 for (const lastLink of select.all('.list-style-none > li:last-of-type', container.element)) { @@ -91,25 +91,26 @@ async function init(): Promise { } } -const getPreviousTag = (index: number, allTags: TagDetails[]): string | false => { - let previousTag: string | false = false; +const getPreviousTag = (current: number, allTags: TagDetails[]): string | undefined => { + let unmatchedNamespaceTag: string | undefined; - for (let i = index + 1; i < allTags.length; i++) { - if (allTags[i].commit === allTags[index].commit) { + for (let next = current + 1; next < allTags.length; next++) { + // Find a version on a different commit, if there are multiple tags on the same one + if (allTags[next].commit === allTags[current].commit) { continue; } - if (allTags[index].namespace === allTags[i].namespace) { - return allTags[i].tag; + if (allTags[current].namespace === allTags[next].namespace) { + return allTags[next].tag; } // If no matching namespace is found, just use the next one - if (previousTag === false) { - previousTag = allTags[i].tag; + if (!unmatchedNamespaceTag) { + unmatchedNamespaceTag = allTags[next].tag; } } - return previousTag; + return unmatchedNamespaceTag; }; features.add({ From 407289b11cced747ff777bd28453c938f7271dee Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 10 May 2019 15:36:48 +0800 Subject: [PATCH 53/54] Ensure that the version is actually a lower one --- source/features/tag-changelog-link.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/features/tag-changelog-link.tsx b/source/features/tag-changelog-link.tsx index eaf0add9f7f..9ca42766dd9 100644 --- a/source/features/tag-changelog-link.tsx +++ b/source/features/tag-changelog-link.tsx @@ -6,6 +6,7 @@ See it in action at: https://github.com/parcel-bundler/parcel/releases */ import React from 'dom-chef'; import select from 'select-dom'; +import tinyVersionCompare from 'tiny-version-compare'; import features from '../libs/features'; import fetchDom from '../libs/fetch-dom'; import * as icons from '../libs/icons'; @@ -100,6 +101,11 @@ const getPreviousTag = (current: number, allTags: TagDetails[]): string | undefi continue; } + // Find an earlier version + if (tinyVersionCompare(allTags[current].version, allTags[next].version) < 1) { + continue; + } + if (allTags[current].namespace === allTags[next].namespace) { return allTags[next].tag; } From aac7d48b790a4374414d49b49f7d5cfb8a89ec1a Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 10 May 2019 15:40:12 +0800 Subject: [PATCH 54/54] Update readme copy --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 11b86b9b3b2..3edd2ac6926 100644 --- a/readme.md +++ b/readme.md @@ -203,8 +203,8 @@ GitHub Enterprise is also supported. More info in the options. - [Follow file renames in commits lists.](https://user-images.githubusercontent.com/1402241/54799957-7306a280-4c9a-11e9-86de-b9764ed93397.png) - [Edit files straight from a repo’s list by clicking their icon.](https://user-images.githubusercontent.com/1402241/56370462-d51cde00-622d-11e9-8cd3-8a173bd3dc08.png) - [Search or select tags from a dropdown in the `Releases` page.](https://user-images.githubusercontent.com/22439276/56373231-27ee9980-621e-11e9-9b21-601919d3dddf.png) -- [See what has changed since the previous release](https://user-images.githubusercontent.com/1402241/57081611-ad4a7180-6d27-11e9-9cb6-c54ec1ac18bb.png) - [Link to file itself in the history pages](https://user-images.githubusercontent.com/22439276/57195061-b88ddf00-6f6b-11e9-8ad9-13225d09266d.png) +- [See an automatic changelog for each tag or release.](https://user-images.githubusercontent.com/1402241/57081611-ad4a7180-6d27-11e9-9cb6-c54ec1ac18bb.png) ### Previously part of Refined GitHub