GitHub one-click sync fork

Sync your GitHub fork repo within one click

当前为 2020-04-07 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub one-click sync fork
  3. // @namespace https://blog.maple3142.net/
  4. // @version 0.4
  5. // @description Sync your GitHub fork repo within one click
  6. // @author maple3142
  7. // @match https://github.com/*
  8. // @require https://unpkg.com/xfetch-js@0.2.3/xfetch.min.js
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @compatible firefox >=52
  12. // @compatible chrome >=55
  13. // ==/UserScript==
  14.  
  15. ;(function () {
  16. 'use strict'
  17. const $ = s => document.querySelector(s)
  18. const $$ = s => [...document.querySelectorAll(s)]
  19. const gh = xf.extend({ baseURI: 'https://api.github.com/' })
  20. const oauthurl = // eslint-disable-next-line max-len
  21. 'https://github.com/login/oauth/authorize?client_id=5c0954a832a0f2bb68f2&scope=repo&redirect_uri=https://github.com/'
  22. // eslint-disable-next-line max-len
  23. const confirmmsg =
  24. 'Are you sure?\nAll the changes you have made will be DELETED!\nIT CANNOT BE RECOVERED!'
  25. const search = new URL(location.href).searchParams
  26. if (search.has('code')) {
  27. const code = search.get('code')
  28. xf.post('https://github.com/login/oauth/access_token', {
  29. json: {
  30. client_id: '5c0954a832a0f2bb68f2',
  31. client_secret: '799a5a49ef0ebde906f8bedc2e3327a99cd0d92a',
  32. code
  33. }
  34. }).text(str => {
  35. const search = new URLSearchParams(str)
  36. GM_setValue('token', search.get('access_token'))
  37. window.close()
  38. })
  39. }
  40.  
  41. const addBtn = () => {
  42. const currentUser = $('.user-profile-link>strong').textContent
  43. const currentRepoOwner = location.pathname.split('/')[1]
  44. const isUserMatch = currentUser === currentRepoOwner
  45. const isFork = !!$('.fork-flag')
  46.  
  47. if (!isUserMatch || !isFork) return
  48. $$('.one-click-sync-fork').forEach(btn => btn.remove())
  49. const repo = location.pathname.split('/').slice(1, 3).join('/')
  50. const upstream = $('.fork-flag a').getAttribute('href').slice(1)
  51. const fnav = $('.file-navigation')
  52. const branchbtn = $('#branch-select-menu')
  53. console.log(branchbtn)
  54. if (!branchbtn) return
  55. const branch =
  56. fnav.querySelector('a').href.split('/').pop() ||
  57. branchbtn.querySelector('summary>span').textContent
  58. const el = document.createElement('div')
  59. el.classList.add('one-click-sync-fork')
  60. el.classList.add('btn')
  61. el.classList.add('btn-sm')
  62. el.classList.add('btn-primary')
  63. el.textContent = `Update fork from ${upstream}/${branch}`
  64. el.onclick = async () => {
  65. const token = GM_getValue('token')
  66. if (!token) {
  67. window.open(oauthurl, '_target')
  68. return
  69. }
  70. if (!confirm(confirmmsg)) return
  71. const sha = await gh
  72. .get(`/repos/${upstream}/branches/${branch}`)
  73. .json(b => b.commit.sha)
  74. await gh
  75. .patch(`/repos/${repo}/git/refs/heads/${branch}`, {
  76. headers: { Authorization: `token ${token}` },
  77. json: { sha, force: true }
  78. })
  79. .json()
  80. location.reload()
  81. }
  82. branchbtn.insertAdjacentElement('afterend', el)
  83. }
  84. addBtn()
  85. new MutationObserver(addBtn).observe(document.body, { childList: true })
  86. })()