From cc34dfb9fbadc18c4fb8bf53aa47080edc72fc33 Mon Sep 17 00:00:00 2001 From: James Chen-Smith <15643597+jameschensmith@users.noreply.github.com> Date: Mon, 11 Sep 2023 11:28:55 -0500 Subject: [PATCH] feat(route): add GitHub Pulse (#13247) * feat(route): add GitHub Pulse * chore: apply suggested changes --------- Co-authored-by: James Chen-Smith --- lib/v2/github/maintainer.js | 1 + lib/v2/github/pulse.js | 87 +++++++++++++++++++ lib/v2/github/radar.js | 6 ++ lib/v2/github/router.js | 1 + lib/v2/github/templates/pulse-description.art | 24 +++++ website/docs/routes/programming.md | 4 + 6 files changed, 123 insertions(+) create mode 100644 lib/v2/github/pulse.js create mode 100644 lib/v2/github/templates/pulse-description.art diff --git a/lib/v2/github/maintainer.js b/lib/v2/github/maintainer.js index 0cdc6b716f..d96156e87e 100644 --- a/lib/v2/github/maintainer.js +++ b/lib/v2/github/maintainer.js @@ -7,6 +7,7 @@ module.exports = { '/issue/:user/:repo/:state?/:labels?': ['HenryQW', 'AndreyMZ'], '/notifications': ['zhzy0077'], '/pull/:user/:repo/:state?': ['hashman', 'TonyRL'], + '/pulse/:user/:repo/:period?': ['jameschensmith'], '/repos/:user': ['DIYgod'], '/search/:query/:sort?/:order?': ['LogicJake'], '/starred_repos/:user': ['LanceZhu'], diff --git a/lib/v2/github/pulse.js b/lib/v2/github/pulse.js new file mode 100644 index 0000000000..7cdc16d63f --- /dev/null +++ b/lib/v2/github/pulse.js @@ -0,0 +1,87 @@ +const cheerio = require('cheerio'); +const path = require('path'); +const got = require('@/utils/got'); +const md5 = require('@/utils/md5'); +const { parseDate } = require('@/utils/parse-date'); +const { art } = require('@/utils/render'); + +module.exports = async (ctx) => { + const { user, repo, period } = ctx.params; + + const periods = ['daily', 'halfweekly', 'weekly', 'monthly']; + const pulsePeriod = periods.includes(period) ? period : periods[2]; + + const link = `https://github.com/${user}/${repo}/pulse/${pulsePeriod}`; + const { data: pulsePage } = await got(link); + const $ = cheerio.load(pulsePage); + + const $mainSections = $('main .Layout-main').children(); + + const $subheading = $mainSections.eq(0); + const [periodFrom, periodTo] = $subheading.find('h2').text().split('–'); + + const $overview = $mainSections.eq(1); + const overviewItems = $overview + .find('ul ul li') + .map((_, el) => $(el).text()) + .toArray(); + + const $commitActivity = $mainSections.eq(2); + let commitActivity; + const $contributionData = $commitActivity.find('.js-pulse-contribution-data'); + if ($contributionData.length) { + const summaryUrl = $contributionData.attr('data-pulse-diffstat-summary-url'); + commitActivity = (await got(`https://github.com${summaryUrl}`)).data; + } else { + commitActivity = $commitActivity.text(); + } + + const $githubActivity = $mainSections.eq(3); + let githubActivity; + const $sections = $githubActivity.find('h3'); + if ($sections.length) { + githubActivity = $sections + .map((_, section) => { + const $section = $(section); + const $sectionSiblings = $section.nextUntil('h3'); + const $paragraph = $section.nextUntil('ul'); + const $list = $sectionSiblings.last(); + return { + heading: $section.text(), + paragraph: $paragraph.length > 0 ? $paragraph.text() : undefined, + items: $list + .children() + .map((_, item) => { + const $item = $(item); + const $link = $item.find('a'); + const $details = $item.find('p'); + const $relativeTime = $details.find('relative-time'); + $relativeTime.replaceWith($relativeTime.attr('datetime')); + return { + link: { text: $link.text(), url: $link.attr('href') }, + details: $details.text(), + }; + }) + .toArray(), + }; + }) + .toArray(); + } + + ctx.state.data = { + title: `${user}/${repo} ${pulsePeriod} Pulse`, + link, + item: [ + { + guid: md5(`${user}${repo}${period}${periodFrom}${periodTo}`), + title: `${periodFrom} - ${periodTo}`, + description: art(path.join(__dirname, 'templates/pulse-description.art'), { + overviewItems, + commitActivity, + githubActivity, + }), + pubDate: parseDate(periodTo), + }, + ], + }; +}; diff --git a/lib/v2/github/radar.js b/lib/v2/github/radar.js index 8fb37f5f0a..b844bda5bf 100644 --- a/lib/v2/github/radar.js +++ b/lib/v2/github/radar.js @@ -44,6 +44,12 @@ module.exports = { source: ['/:user/:repo/pulls', '/:user/:repo/pulls/:id', '/:user/:repo'], target: '/github/pull/:user/:repo', }, + { + title: 'Pulse', + docs: 'https://docs.rsshub.app/routes/programming#github', + source: ['/:user/:repo/pulse', '/:user/:repo/pulse/:period'], + target: '/github/pulse/:user/:repo/:period?', + }, { title: '用户仓库', docs: 'https://docs.rsshub.app/routes/programming#github', diff --git a/lib/v2/github/router.js b/lib/v2/github/router.js index 7b8f52b4a2..dcd838658f 100644 --- a/lib/v2/github/router.js +++ b/lib/v2/github/router.js @@ -8,6 +8,7 @@ module.exports = function (router) { router.get('/issue/:user/:repo/:state?/:labels?', require('./issue')); router.get('/notifications', require('./notifications')); router.get('/pull/:user/:repo/:state?/:labels?', require('./pulls')); + router.get('/pulse/:user/:repo/:period?', require('./pulse')); router.get('/repos/:user', require('./repos')); router.get('/search/:query/:sort?/:order?', require('./search')); router.get('/starred_repos/:user', require('./starred_repos')); diff --git a/lib/v2/github/templates/pulse-description.art b/lib/v2/github/templates/pulse-description.art new file mode 100644 index 0000000000..d5580e7dd9 --- /dev/null +++ b/lib/v2/github/templates/pulse-description.art @@ -0,0 +1,24 @@ +

Overview

+ + + +{{@ commitActivity}} + +{{each githubActivity activity}} +

{{activity.heading}}

+ {{if activity.paragraph}} +

{{activity.paragraph}}

+ {{/if}} + +{{/each}} \ No newline at end of file diff --git a/website/docs/routes/programming.md b/website/docs/routes/programming.md index cbfc31d7f9..c82c88b2f3 100644 --- a/website/docs/routes/programming.md +++ b/website/docs/routes/programming.md @@ -316,6 +316,10 @@ For instance, the `/github/topics/framework/l=php&o=desc&s=stars` route will gen +### Repo Pulse {#github-repo-pulse} + + + ### User Followers {#github-user-followers}