国内的开发者们,有使用 github 上开源的代码仓库上通过提交 issue 的方式进行一些技术或者非技术层面的讨论。
由于众所周知的原因,有些代码仓库并不总是可用,有时候会因为一些不可抗力的原因被删除。
此时就有了将 Github Repository 上某些有价值的 issue 的内容,保存到本地永久存储起来,比如以 text 文本文件的格式存储。
采用手动方式一个 issue 一个 issue 备份的方式比较愚蠢,因此我们可以动手写一个备份工具。
本文笔者选用了 Node.js 作为开发工具。
我们首先找一个例子,比如这个 Github issue:
https://github.com/SAP/openui5/issues/4176
浏览器打开之后,issue 内容如下:
要想使用 Node.js 将这个 issue 的内容下载到本地,我们需要使用 Github API 这个工具。
GitHub API 是一种用于与 GitHub 平台交互的编程接口,其实也就是一组 Restful API 的集合啦,它允许开发者通过编写代码来访问 GitHub 上的资源和数据。
https://api.github.com/repos/
是其中一个重要的端点,主要用于操作 GitHub 上的代码仓库资源。
API 的核心功能是为用户提供一种以编程方式访问和操作 GitHub 平台数据的方法,而不是通过用户界面手动操作。例如,通过 API,开发者可以获取仓库的详细信息,创建新仓库,修改现有仓库的设置,甚至删除仓库。
GitHub API 的 repos
端点主要围绕代码仓库展开,支持多种操作。这个端点的基本结构如下:
https://api.github.com/repos/{owner}/{repo}
其中,{owner}
是仓库所有者的用户名或组织名,{repo}
是具体的仓库名称。例如:
https://api.github.com/repos/octocat/Hello-World
这个 URL 用于访问 octocat
用户的 Hello-World
仓库。
本文要使用的 API 是下面这个 API endpoint:
https://api.github.com/repos/{owner}/{repo}/issues
:允许开发者获取仓库中的公开问题,包括问题标题、状态、作者和标签等信息。
GitHub API 实施速率限制,默认每小时允许 5000 次认证请求和 60 次未认证请求。如果用户的请求频率过高,可以使用 X-RateLimit-Remaining
标头查看剩余请求额度。
我们使用 Node.js 里的 https 工具库,来调用 Github API.
https 模块是 Node.js 内置的工具库,专门用于处理 HTTPS(Hyper Text Transfer Protocol Secure)协议。HTTPS 是 HTTP 的安全版本,利用 SSL/TLS 协议对传输内容进行加密,确保数据的保密性、完整性和真实性。在现代网络中,HTTPS 被广泛用于保护用户隐私,特别是在处理敏感数据(如密码、信用卡号)时。
我们想下载的 Github issue 的原始 url:
https://github.com/SAP/openui5/issues/4176
转换成对应的 Github API url 为:https://api.github.com/repos/SAP/openui5/issues/4176
浏览器里访问这个 url,得到 API response 如下:
所以这个工具的开发步骤如下。
这里我们使用 Node.js 工具库 readline 来解析用户输入。这个工具库专门用于处理命令行交互。它的功能主要包括从可读流中逐行读取数据,以及通过接口实现用户与程序之间的交互。对于构建命令行工具、接受用户输入或处理标准输入输出的数据流,readline 是一个非常强大的工具。
我把逻辑封装在函数 fetchGithubIssues 里,并添加了相应的错误处理。
本例完整的代码在文末。
我们将所有的逻辑实现在 download.js
文件里,然后用命令行 node download.js
启动这个 Node.js 应用。
执行之后,输入要下载的 Github issue url,工具就会打印出实际的 Github API url,并将该 issue 的内容通过 https 读取到本地,另存为 text 文件。
打开本地文件,发现下载成功:
本文完整的源代码:
// 引入必要的库
const https = require('https');
const fs = require('fs');
const path = require('path');
const readline = require('readline');
// 创建一个函数用来下载 Github Issue 的内容
function fetchGithubIssue(issueUrl, outputFilePath) {
// 验证 URL 格式
const urlPattern = /^https:\/\/github\.com\/[^\/]+\/[^\/]+\/issues\/\d+$/;
if (!urlPattern.test(issueUrl)) {
console.error('请输入有效的 Github Issue URL,例如:https://github.com/owner/repo/issues/1');
process.exit(1);
}
// 提取 API URL
const apiUrl = issueUrl.replace('https://github.com/', 'https://api.github.com/repos/').replace('/issues/', '/issues/');
// 配置请求头
const options = {
headers: {
'User-Agent': 'Node.js Application',
'Accept': 'application/vnd.github.v3+json',
},
};
// 发送 HTTPS 请求获取 Issue 数据
https.get(apiUrl, options, (res) => {
let data = '';
if (res.statusCode !== 200) {
console.error(`请求失败,状态码: ${res.statusCode}`);
res.resume();
return;
}
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
try {
const issue = JSON.parse(data);
const content = `Issue Title: ${issue.title}\n\n` +
`Issue Body:\n${issue.body || '无内容'}\n\n` +
`URL: ${issueUrl}\n`;
// 将内容保存到指定文件
fs.writeFileSync(outputFilePath, content, 'utf-8');
console.log(`Issue 已成功保存到 ${outputFilePath}`);
} catch (err) {
console.error('解析响应数据时出错:', err.message);
}
});
}).on('error', (err) => {
console.error('请求过程中出错:', err.message);
});
}
// 创建命令行接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('请输入 Github Issue 的 URL: ', (url) => {
const outputFilePath = path.resolve(__dirname, 'issue.txt');
fetchGithubIssue(url, outputFilePath);
rl.close();
});
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。