(page: number = 1, perPage: number = 30)
| 116 | |
| 117 | // 获取所有 issues |
| 118 | static async getIssues(page: number = 1, perPage: number = 30): Promise<Article[]> { |
| 119 | const cacheKey = `issues_${page}_${perPage}`; |
| 120 | const cached = cache.get<Article[]>(cacheKey); |
| 121 | if (cached) { |
| 122 | return cached; |
| 123 | } |
| 124 | |
| 125 | try { |
| 126 | const url = `${this.BASE_URL}/repos/${this.REPO_OWNER}/${this.REPO_NAME}/issues?state=open&sort=created&direction=desc&page=${page}&per_page=${perPage}`; |
| 127 | |
| 128 | const response = await this.fetchWithRetry(url, { |
| 129 | headers: this.getHeaders() |
| 130 | }); |
| 131 | |
| 132 | if (!response.ok) { |
| 133 | console.error(`GitHub API error: ${response.status} - ${response.statusText}`); |
| 134 | // 如果是限流错误,返回空数组而不是抛出错误 |
| 135 | if (response.status === 403) { |
| 136 | console.error('GitHub API rate limit exceeded'); |
| 137 | return []; |
| 138 | } |
| 139 | return []; |
| 140 | } |
| 141 | |
| 142 | const issues: GitHubIssue[] = await response.json(); |
| 143 | |
| 144 | // 调试:打印每个 issue 的作者和标题 |
| 145 | console.log('GitHub issues user:', issues.map(i => ({user: i.user.login, title: i.title}))); |
| 146 | |
| 147 | if (!Array.isArray(issues)) { |
| 148 | console.error('GitHub API returned non-array issues:', issues); |
| 149 | return []; |
| 150 | } |
| 151 | |
| 152 | console.log('issues', issues); |
| 153 | |
| 154 | // 过滤掉非文章类型的 issue(如 bug 报告等) |
| 155 | const articleIssues = issues.filter(issue => { |
| 156 | // 只排除明显的非文章内容 |
| 157 | const excludeKeywords = ['bug', '问题', '建议', '求助', 'question', 'help', 'error']; |
| 158 | const hasExcludeKeyword = excludeKeywords.some(keyword => |
| 159 | issue.title.toLowerCase().includes(keyword.toLowerCase()) |
| 160 | ); |
| 161 | |
| 162 | // 排除用户不是 chokcoco 的 issue(通常是用户提问) |
| 163 | const isAuthor = issue.user.login === 'chokcoco'; |
| 164 | |
| 165 | return !hasExcludeKeyword && isAuthor; |
| 166 | }); |
| 167 | |
| 168 | console.log('Filtered issues count:', articleIssues.length); |
| 169 | console.log('Filtered issues:', articleIssues.map(i => ({user: i.user.login, title: i.title}))); |
| 170 | |
| 171 | const articles = articleIssues.map(issue => this.transformIssueToArticle(issue)); |
| 172 | |
| 173 | console.log('Transformed articles count:', articles.length); |
| 174 | console.log('Transformed articles:', articles.map(a => ({id: a.id, title: a.title}))); |
| 175 |
no test coverage detected