node.js具有一个new RSS feed,可合并来自不同团队,工作组和项目的所有发布和新闻。
挑战
node.js作为组织一直在持续很多事情。有许多项目,团队和工作组从事不同的事情。很难跟踪正在发生的所有事情,因此,社区需要经常需要找到一种更好的方法来了解正在发生的事情。 This discussion持续了一段时间,关于如何解决这个问题有很多想法,但是我们认为RSS是一种开始的好方法,因为这也将有助于促进Node.js org本身以外的我们的活动和成就。
要求
- 团队和工作组应该能够添加自己的新闻,而不必改变工作方式(没有PRS,表格...)
- 该信息应在有效的RSS feed中获得。
- 应自动更新提要,但允许手动新闻和简单的内容策划。
做出的决定
- 使用github作为新闻的真实来源,因此我们将使用github api从问题,讨论,发行中获取相关信息...
- 使用github操作生成RSS feed并将其发布到github页面。
- 使用GitHub操作每周或在需要时自动更新供稿,并通过团队将审查和策划的PR的更改生成新的提交。
- 尽可能避免外部依赖性,因此解决方案应具有独立且易于维护。
解决方案
可以在this repository中找到完整的源代码。我将在此处解释解决方案中最相关的部分。
架构
一般而言,该解决方案由以下部分组成:
社区
社区是新闻的来源。他们是回答与新闻提要有关的特定问题或讨论以及管理新版本的人。
策展人
策展人是审查更改并合并更新提要的PR的人。该提要每周会自动更新,但也可以在需要时手动更新。有几个脚本可以收集,处理,验证和发布提要。
读者
读者是消耗饲料的人。他们可以是人类或机器人。读者可以使用以下URL订阅Feed:https://nodejs.github.io/nodejs-news-feeder/feed.xml
。我们提供了一个Slack频道,在该频道中自动发布了供稿,因此社区可以了解最新消息。
结构
配置
有一个config.json file将所有引用存储到外部资源(讨论,问题,发行...),API速率限制以及最后执行时间的配置(lastCheckTimestamp
)。
最后一个执行时间(lastCheckTimestamp
)将阻止我们在提要中包含已经处理过的信息。这样可以防止我们使用第三方软件或调解提要以避免重复。
{
"lastCheckTimestamp": 1688584036809,
"reposPaginationLimit": 250,
"releasePaginationLimit": 10,
"commentsPaginationLimit": 100,
"breakDelimiter": "</image>",
"discussionsInScope": [],
"issuesInScope": []
}
模块化
该解决方案分为不同的脚本,这些脚本可以做不同的事情,这使我们可以重复使用代码并使其更容易维护。
通过检查the package.json。
这种结构更清晰
{
"scripts": {
"collect:releases": "node scripts/collect-releases.js",
"collect:issues": "node scripts/collect-issues.js",
"collect:discussions": "node scripts/collect-discussions.js",
"rss:validate": "node scripts/validate.js",
"rss:build": "node scripts/build.js",
"rss:format": "node scripts/format.js",
"rss:format-check": "node scripts/format-check.js"
}
}
从github获取内容
发行
node.js使用github版本发布不同项目的新版本。组织中有许多项目,我们会定期添加更多。
因此,this script将执行以下操作:
- 获取组织中的所有存储库。
- 获取每个存储库的最新版本。
- 通过比最后一个执行时间更新的版本过滤释放(
lastCheckTimestamp
)。 - 格式化要包含在feed中的版本。
- 将释放添加到供稿中。
问题
每个项目都以响应方式在github问题上发布其新闻。
所以,this script:
- 在范围中的问题中获取所有评论。
- 过滤了比上一个执行时间更新的评论(
lastCheckTimestamp
)。 - 格式化要包含在提要中的评论。
- 将评论添加到提要中。
讨论
讨论与问题非常相似,但是在github api休息中不支持它们,因此我们使用GitHub GraphQL API获取评论。
const comments = await Promise.all(discussionsInScope.map(async ({ discussionId, team }) => {
const { repository } = await graphql(
`
{
repository(name: "node", owner: "nodejs") {
discussion(number: ${discussionId}) {
comments(last: 100) {
edges {
node {
body
publishedAt
updatedAt
databaseId
}
}
}
}
}
}
`,
{
headers: {
authorization: `token ${process.env.GITHUB_TOKEN}`
}
}
)
return repository.discussion.comments.edges
.filter(comment => new Date(comment.node.publishedAt).getTime() > lastCheckTimestamp)
.map(comment => ({ ...comment.node, team, discussionId }))
}))
See the full file有关更多详细信息
更新提要
为了更新提要,我们需要将当前feed拆分为config.json文件中定义的breakDelimiter
。
//...OMITED...
const feedContent = getFeedContent()
const [before, after] = feedContent.split(breakDelimiter)
const updatedFeedContent = `${before}${breakDelimiter}${relevantReleases}${after}`
overwriteFeedContent(updatedFeedContent)
See the full file有关更多详细信息
格式化饲料
我们使用库xml-formatter来使饲料含量正常化。这将有助于我们在审查pr时稍后策划内容。
import xmlFormat from 'xml-formatter'
import { getFeedContent, overwriteFeedContent } from '../utils/index.js'
const xml = getFeedContent()
const formattedXml = xmlFormat(xml, { indentation: ' ', collapseContent: true })
overwriteFeedContent(formattedXml)
See the full file有关更多详细信息
验证饲料
为了验证提要,我们直接使用带有HTTP请求的W3C Feed Validation Service,模拟表单(使用got库)并解析响应。
const data = await got.post('https://validator.w3.org/feed/check.cgi', {
form: {
rawdata: xml,
manual: 1
}
}).text()
// Avoid importing CSS in the document
const dom = new JSDOM(data.replace(/@import.*/gm, ''))
const title = dom.window.document.querySelector('h2').textContent
const recommendations = dom.window.document.querySelector('ul').textContent
console.log(recommendations)
if (title === 'Sorry') {
console.log('🚨 Feed is invalid!')
process.exit(1)
} else {
console.log('✅ Feed is valid!')
}
注意:要使用库jsdom刮擦HTML响应,我们需要避免CSS中的@import
语句。
github动作
Cron Job和手动触发器
github操作配置为每周运行,但可以使用workflow_dispatch
事件手动触发。当我们想手动更新供稿时,这很有用,例如,当我们想添加GitHub上无法使用或只是想快速推广一些新闻时。
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0'
# ...OMITED...
See the full file有关更多详细信息
API限制
GitHub API对请求有限制。此过程向API提出了许多请求,因此克服此限制的最佳方法是使用GitHub令牌。
这个令牌可以由用户创建,然后添加到存储库秘密中。 GitHub操作将使用此令牌来验证对API的请求,并且它的限制将比匿名请求更高。
,但最好的解决方案是在github操作中使用已有的令牌:
# ...OMITED...
permissions:
contents: write
pull-requests: write
issues: read
packages: none
jobs:
build:
runs-on: ubuntu-latest
steps:
# ...OMITED...
- name: Collect Releases
run: npm run collect:releases
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ...OMITED...
See the full file有关更多详细信息
我们将secrets.GITHUB_TOKEN
作为环境变量GITHUB_TOKEN
传递给脚本。
松弛通知
使用RSS App在Slack上发布该提要。该应用程序正在收听提要,并将新项目推向特定的频道。在我们的情况下,我们使用的是kude10。
致谢
非常感谢Node.js Next 10 team对该项目的支持和反馈,尤其是对Michael Dawson的指南,评论和建议。