// ==UserScript== // @name GitHub First Commit // @description Add a link to a GitHub repo's first commit // @author chocolateboy // @copyright chocolateboy // @version 2.7.1 // @namespace https://github.com/chocolateboy/userscripts // @license GPL: https://www.gnu.org/copyleft/gpl.html // @include https://github.com/ // @include https://github.com/* // @require https://cdn.jsdelivr.net/npm/cash-dom@8.1.0/dist/cash.min.js // @grant GM_log // @inject-into auto // @downloadURL none // ==/UserScript== const COMMIT_BAR = 'div.js-details-container[data-issue-and-pr-hovercards-enabled] > *:last-child ul' const FIRST_COMMIT_LABEL = '1st commit' /* * this function extracts the URL of the repo's first commit and navigates to it. * it is based on code by several developers, a list of whom can be found here: * https://github.com/FarhadG/init#contributors * * XXX it doesn't work on private repos. a way to do that can be found here, * but it requires an authentication token: * https://gist.github.com/simonewebdesign/a70f6c89ffd71e6ba4f7dcf7cc74ccf8 */ function openFirstCommit (user, repo) { return fetch(`https://api.github.com/repos/${user}/${repo}/commits`) // the `Link` header has additional URLs for paging. // parse the original JSON for the case where no other pages exist .then(res => Promise.all([res.headers.get('link'), res.json()])) .then(([link, commits]) => { if (link) { // the link header contains two URLs and has the following // format (wrapped for readability): // // ; // rel="next", // ; // rel="last" // extract the URL of the last page (commits are ordered in // reverse chronological order, like the git CLI, so the oldest // commit is on the last page) // @ts-ignore const lastPage = link.match(/^.+?<([^>]+)>;/)[1] // fetch the last page of results return fetch(lastPage).then(res => res.json()) } // if there's no link, we know we're on the only page return commits }) // get the last commit and navigate to its target URL .then(commits => { location.href = commits[commits.length - 1].html_url }) } /* * add the "First commit" link as the last child of the commit bar */ function run () { const $commitBar = $(COMMIT_BAR) // bail if it's not a repo page if (!$commitBar.length) { return } // delete (i.e. replace) the (possibly inert/unresponsive) widget if it // already exists $commitBar.find('#first-commit').remove() /* * This is the first LI in the commit bar (UL), which we clone to create the * "First commit" widget. * *
  • * * ... * * * 42 * commits * * *
  • */ // create it const $firstCommit = $commitBar .find('li') .eq(0) .clone() .attr('id', 'first-commit') const $link = $firstCommit .find('a') .removeAttr('href') .css('cursor', 'pointer') const $label = $(FIRST_COMMIT_LABEL) $link.find(':scope > span').empty().append($label) // @ts-ignore const [user, repo] = $('meta[name="octolytics-dimension-repository_network_root_nwo"]') .attr('content') .split('/') $link.on('click', () => { $label.text('Loading...') openFirstCommit(user, repo) return false // stop processing the click }) $commitBar.append($firstCommit) } $(document).on('pjax:end', run) // run on pjax page loads $(run) // run on full page loads