前言
上星期四,我像往常一样起床上班,地铁上收到了微信消息
这时候就感觉到不对劲了,到了公司我登录了自己的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); } })();