共计 6768 个字符,预计需要花费 17 分钟才能阅读完成。
点击在线浏览,体验更好 | 链接 |
---|---|
古代 JavaScript 高级小册 | 链接 |
深入浅出 Dart | 链接 |
古代 TypeScript 高级小册 | 链接 |
linwu 的算法笔记📒 | 链接 |
前言
上星期四,我像平常一样起床下班,地铁上收到了微信音讯
这时候就感觉到不对劲了,到了公司我登录了本人的 github,发现被封了
毫无征兆,我的 gmail 也没有收到 github 邮箱。
因为这个 github 账号我始终用来寄存 我的网站材料以及 blog
,所以很多 issue 都在外面,另外还有局部 图床和博客示例
, 这个被封禁,所有材料都迁徙不了
原因
网上查了一圈,发现 github 被封,很少能申述胜利的,所以我给官网发了一封邮件,想看看是什么起因导致的,防止后续再呈现相似的问题
给官网回了一个邮件后,过了半个小时我收到了回复
原来问题是这样,因为我之前找某宝开明了 copilot 学生认证
,导致被 github 查到封禁了,至于之所以找某宝,是因为我没有visa 卡
领取起来麻烦,又想体验 copilot
,没方法才出此下策,所以copilot 学生认证
还是不要绑定本人的 github 账号吧
迁徙
封都曾经封了,这时候就得统计损失了,尽量挽回
所幸我很多仓库本地都有备份,从新注册了一个 github 账号上传就行,为此我还专门写了些脚本
备份 star
很多同学都会把 star 当做书签收集
这时候能够通过拜访 github api 进行备份
https://api.github.com/users/[username]/starred
批量备份 issue 到本地
const fs = require('fs');
const axios = require('axios');
const sanitize = require('sanitize-filename');
const {githubRepoOwner, githubRepoName, githubAccessToken} = require('./config');
async function getIssues() {let allIssues = [];
let page = 1;
let perPage = 300; // 每页返回 100 个 issue,依据理论状况能够适当调整
try {while (true) {const response = await axios.get(`https://api.github.com/repos/${githubRepoOwner}/${githubRepoName}/issues`, {
params: {
page,
per_page: perPage
},
headers: {Authorization: `Bearer ${githubAccessToken}`
}
});
const issues = response.data;
if (issues.length === 0) {break; // 退出循环,示意已获取所有 issue 数据}
allIssues = allIssues.concat(issues);
page++;
}
return allIssues;
} catch (error) {throw new Error(`Error fetching issues: ${error.message}`);
}
}
async function saveIssueAsMarkdown(issue, directory) {
const markdownContent = issue.body;
const fileName = `${directory}/${sanitize(issue.title)}.md`;
fs.writeFileSync(fileName, markdownContent);
}
async function main() {
try {const issues = await getIssues();
// Create a directory for each label
issues.forEach(issue => {
issue.labels.forEach(label => {const directory = `./docs/${sanitize(label.name)}`;
if (!fs.existsSync(directory)) {fs.mkdirSync(directory, { recursive: true});
}
saveIssueAsMarkdown(issue, directory);
});
});
console.log('Markdown files saved successfully!');
} catch (error) {console.error(error.message);
}
}
main();
批量更新 issue 题目
const {Octokit} = require('@octokit/rest');
// GitHub personal access token
const token = '';
// GitHub repository information
const owner = 'LQ-vic';
const repo = 'code-interview';
const labelToFilter = 'image'; // 请替换为你想筛选的标签
const octokit = new Octokit({auth: token});
async function updateIssueTitlesByLabel() {
try {
// 依据标签获取仓库的所有 issues
const issues = await octokit.issues.listForRepo({
owner,
repo,
state: 'open', // 只获取关上的 issues
labels: labelToFilter,
per_page: 100, // 每页获取 100 个 issues,你能够依据须要调整
});
for (const issue of issues.data) {if (issue.title.startsWith('xx:xx:')) {const newTitle = issue.title.replace('xx:xx:', 'xx:');
await octokit.issues.update({
owner,
repo,
issue_number: issue.number,
title: newTitle,
});
console.log(`Updated issue #${issue.number} title to: ${newTitle}`);
}
}
} catch (error) {console.error('Error updating issue titles:', error.message);
}
}
updateIssueTitlesByLabel();
批量上传 issue
const fs = require('fs');
const path = require('path');
const {Octokit} = require('@octokit/rest');
// GitHub personal access token
const token = '';
// GitHub repository information
const owner = 'LQ-vic';
const repo = 'code-interview';
// Directory path of the docs folder
const docsDirectory = './docs/CSS3';
// Labels to be added to each issue
const labelColors = [{ name: 'CSS3', color: '#FBCA033'}
];
const excludedDirectories = ['.vuepress', '.git', 'node_modules'];
// File path to store the uploaded files record
const recordFilePath = './uploaded_files.txt';
// Initialize Octokit
const octokit = new Octokit({auth: token});
// Function to read all Markdown files in the given directory
async function readMarkdownFiles(directory) {const files = fs.readdirSync(directory);
for (const file of files) {// console.log('file',file)
const filePath = path.join(directory, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory() && !excludedDirectories.includes(file)) {await readMarkdownFiles(filePath); // Recursively read files in non-excluded subdirectories
} else if (stat.isFile() && path.extname(file) === '.md') {const content = fs.readFileSync(filePath, 'utf8');
const title = extractTitleFromContent(content);
if (!isFileUploaded(title)) {await createIssue(title, content, labelColors);
addUploadedFile(title);
}
}
}
}
// Function to create GitHub issue
async function createIssue(title, body, labels) {
try {
const response = await octokit.issues.create({
owner: owner,
repo: repo,
title: `${title}`,
body: body,
labels: labels
});
console.log(`Successfully created issue: ${title}`);
} catch (error) {console.log(`Failed to create issue: 面试官:${title}`);
console.log(`Error: ${error.message}`);
}
}
// Function to extract title from the content (first heading)
function extractTitleFromContent(content) {const match = content.match(/^#\s*(.+)/);
if (match) {return match[1];
}
return '';
}
// Function to check if a file has been uploaded
function isFileUploaded(filename) {if (fs.existsSync(recordFilePath)) {const uploadedFiles = fs.readFileSync(recordFilePath, 'utf8').split('\n');
return uploadedFiles.includes(filename);
}
return false;
}
// Function to add uploaded file to the record
function addUploadedFile(filename) {fs.appendFileSync(recordFilePath, filename + '\n', 'utf8');
}
// Read all Markdown files in the docs directory (excluding specified directories) and create issues
readMarkdownFiles(docsDirectory)
.then(() => {console.log('All issues created.');
})
.catch((error) => {console.log('Error:', error);
});
批量导出 issue 目录
const axios = require('axios');
const fs = require('fs');
async function getGitHubIssues(owner, repo, labels, token) {const baseUrl = `https://api.github.com/repos/${owner}/${repo}/issues`;
const headers = token ? {Authorization: `token ${token}` } : {};
const params = {state: 'all', per_page: 100};
const issuesByLabel = {};
let nextPage = true;
while (nextPage) {
try {const response = await axios.get(baseUrl, { headers, params});
const data = response.data;
if (!data.length) break;
data.forEach((issue) => {if (!issue.pull_request) {issue.labels.forEach((label) => {if (labels.includes(label.name)) {if (!issuesByLabel[label.name]) {issuesByLabel[label.name] = [];}
issuesByLabel[label.name].push(issue);
}
});
}
});
if (response.headers.link) {const links = response.headers.link.split(',');
nextPage = links.some((link) => link.endsWith('rel="next"'));
if (nextPage) {const nextPageNum = parseInt(links[links.length - 1].match(/&page=(\d+)/)[1], 10);
params.page = nextPageNum;
}
} else {nextPage = false;}
} catch (error) {throw new Error(`Failed to fetch issues. Error: ${error.message}`);
}
}
return issuesByLabel;
}
// Output to Markdown file
function writeIssuesToMarkdown(issues, outputPath) {
let content = '';
Object.entries(issues).forEach(([label, issuesList]) => {content += `## ${label}\n\n`;
issuesList.forEach((issue) => {content += `- [${issue.title}](${issue.html_url})\n`;
});
content += '\n';
});
fs.writeFile(outputPath, content, (err) => {if (err) {console.error('Error writing the file:', err);
} else {console.log('Markdown file generated successfully!');
}
});
}
// 应用示例
const owner = 'LQ-vic';
const repo = 'code-interview';
const labels = ['JavaScript', 'TypeScript','vue','vue3','react','HTTP','webpack','nodejs','Linux','git','CSS','CSS3','组件库','小程序'];
const token = '';
const outputPath = 'dirname.md';
(async () => {
try {const issues = await getGitHubIssues(owner, repo, labels, token);
writeIssuesToMarkdown(issues, outputPath);
} catch (error) {console.error(error.message);
}
})();
正文完