在開源項目中,Issues是一個強大的功能,用于跟蹤bug、功能請求和任務。然而,隨著項目的發展,Issues可能會變得難以管理,特別是當你需要離線訪問或進行深入分析時。
當然GitHub Issues除了上述功能以外,做在線筆記也非常的方便,它支持Markdown語法,還能打標簽、分層等等,還天然的支持評論功能。由于我本人就非常熱衷于使用Issue做筆記,但是問題就是在離線環境下無法使用,那么能不能把Issue作為離線Markdown文件下載到本地呢?
答案顯然是可以的,也是我本次項目的主要功能之一。
issue2file
是一個用Go語言編寫的命令行工具,它可以將GitHub倉庫中的Issues導出為本地Markdown文件,并提供多種強大的功能:
1)完整內容保留:保留Issue的標題、內容、標簽、狀態、創建時間等信息
2)評論支持:可選擇性地下載Issue的所有評論
除此之外,我想了想能不能通過AI擴展一下?答案顯然也是可以的,所以還補充了如下功能:
3)AI分析:集成AI功能,可以對Issues進行智能分析和總結
4)數據可視化:自動生成多種圖表,包括Issue狀態分布、標簽分布和時間趨勢等
項目介紹
還是先說一下使用方式吧,當然如果想要支持私有倉庫和AI功能的話,需要拿到自己的Github Token和DeepSeek的API Token。
1)倉庫地址
https://github.com/ibarryyan/issue2file
2)工具構建
go mod tidy
go build
3)使用方式
最簡單的使用方式就是直接運行可執行文件,加上倉庫鏈接作為參數,比如
./issue2file ibarryyan/golang-tips-100
如果想要拉取自己的私有倉庫就要先生成一個自己的Github Token,然后使用命令行參數或者配置文件進行啟動,詳細說明可以參考:
https://github.com/ibarryyan/issue2file/blob/master/README.md
當然了,還有額外的參數能支持生成圖表分析倉庫的所有Issue,主要有Issue創建時間趨勢、狀態分析和標簽分布等幾個維度:
技術實現
issue2file
采用模塊化設計,主要包含以下幾個核心組件:
1)配置管理:使用Viper庫處理配置文件
2)GitHub API交互:使用go-github庫獲取Issues數據
3)Markdown生成:將Issue數據轉換為Markdown格式
4)AI分析:集成AI能力對Issues進行分析
5)圖表生成:使用go-echarts庫生成數據可視化圖表
關鍵技術點
1)配置管理
項目使用Viper庫來處理配置,支持從配置文件中讀取各種參數:
func InitConfig() {viper.SetConfigName("config")viper.SetConfigType("conf")viper.AddConfigPath(".")if err := viper.ReadInConfig(); err != nil {log.Fatalf("Error reading config file: %s", err)}// 讀取配置項Config.GitHubToken = viper.GetString("gitHubToken")Config.AIToken = viper.GetString("aiToken")Config.CommentEnable = viper.GetBool("commentEnable")Config.AIEnable = viper.GetBool("aiEnable")Config.ChartEnable = viper.GetBool("chartEnable")Config.OutputDir = viper.GetString("outputDir")Config.SummaryFile = viper.GetString("summaryFile")
}
2)GitHub API交互
使用go-github庫與GitHub API進行交互,獲取Issues數據:
func FetchIssues(owner, repo string) ([]*github.Issue, error) {ctx := context.Background()ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: Config.GitHubToken},)tc := oauth2.NewClient(ctx, ts)client := github.NewClient(tc)opt := &github.IssueListByRepoOptions{State: "all",Sort: "created",Direction: "desc",ListOptions: github.ListOptions{PerPage: 100,},}var allIssues []*github.Issuefor {issues, resp, err := client.Issues.ListByRepo(ctx, owner, repo, opt)if err != nil {return nil, err}allIssues = append(allIssues, issues...)if resp.NextPage == 0 {break}opt.Page = resp.NextPage}return allIssues, nil
}
3)Markdown生成
將Issue數據轉換為結構化的Markdown文件:
func GenerateMarkdown(issue *github.Issue, comments []*github.IssueComment) string {var md strings.Builder// 添加標題md.WriteString(fmt.Sprintf("# %s\n\n", *issue.Title))// 添加元數據md.WriteString(fmt.Sprintf("- **Issue編號**: #%d\n", *issue.Number))md.WriteString(fmt.Sprintf("- **創建者**: %s\n", *issue.User.Login))md.WriteString(fmt.Sprintf("- **創建時間**: %s\n", issue.CreatedAt.Format("2006-01-02 15:04:05")))md.WriteString(fmt.Sprintf("- **狀態**: %s\n", *issue.State))// 添加標簽if len(issue.Labels) > 0 {md.WriteString("- **標簽**: ")for i, label := range issue.Labels {if i > 0 {md.WriteString(", ")}md.WriteString(*label.Name)}md.WriteString("\n")}// 添加正文md.WriteString("\n## 內容\n\n")md.WriteString(*issue.Body)// 添加評論if len(comments) > 0 {md.WriteString("\n\n## 評論\n\n")for _, comment := range comments {md.WriteString(fmt.Sprintf("### %s 評論于 %s\n\n", *comment.User.Login, comment.CreatedAt.Format("2006-01-02 15:04:05")))md.WriteString(*comment.Body)md.WriteString("\n\n---\n\n")}}return md.String()
}
4)AI分析
集成AI能力,對Issues進行智能分析和總結:
func AnalyzeIssues(issues []*github.Issue) (string, error) {if !Config.AIEnable || Config.AIToken == "" {return "", errors.New("AI analysis is disabled or token is not provided")}// 準備AI分析的輸入數據var input strings.Builderinput.WriteString("請分析以下GitHub Issues,并提供總結報告:\n\n")for _, issue := range issues {input.WriteString(fmt.Sprintf("Issue #%d: %s\n", *issue.Number, *issue.Title))input.WriteString(fmt.Sprintf("狀態: %s\n", *issue.State))input.WriteString(fmt.Sprintf("創建時間: %s\n", issue.CreatedAt.Format("2006-01-02")))input.WriteString("標簽: ")for i, label := range issue.Labels {if i > 0 {input.WriteString(", ")}input.WriteString(*label.Name)}input.WriteString("\n\n")// 限制內容長度,避免超出AI API的限制body := *issue.Bodyif len(body) > 500 {body = body[:500] + "..."}input.WriteString(body)input.WriteString("\n\n---\n\n")}// 調用AI API進行分析analysis, err := callAIAPI(input.String())if err != nil {return "", err}return analysis, nil
}
5)圖表生成
使用go-echarts庫生成數據可視化圖表:
func GenerateCharts(issues []*github.Issue, outputDir string) error {if !Config.ChartEnable {return nil}// 生成狀態分布圖if err := generateStatusChart(issues, outputDir); err != nil {return err}// 生成標簽分布圖if err := generateTagsChart(issues, outputDir); err != nil {return err}// 生成時間趨勢圖if err := generateTimeChart(issues, outputDir); err != nil {return err}return nil
}
全部代碼目前已經開源,大家可以去Github上拉取~~
開源成果
issue2file
項目在開源后的一周內就獲得了29個star,這種積極的社區反饋不僅驗證了項目的價值,也為未來的發展提供了動力。
在這里主要感謝@ruanyf老師在《科技愛好者周刊》中的推薦!
總結與規劃
issue2file
成功地實現了將GitHub Issues轉換為本地Markdown文件的核心功能,并通過AI分析和數據可視化等特性提供了額外的價值。
基于社區反饋和項目愿景,未來的發展計劃包括:
功能增強:
- 添加增量更新功能,只下載新的或更新的Issues
- 增強AI分析能力,提供更深入的洞察
用戶體驗改進:
- 提供Web界面,使非技術用戶也能輕松使用
- 添加進度顯示和更詳細的日志
- 完善文檔和示例
如果你對這個項目感興趣,歡迎訪問GitHub倉庫(https://github.com/ibarryyan/issue2file
),給項目點個star,或者貢獻代碼!