LoginSignup
9
1

More than 1 year has passed since last update.

TODOコメントを埋もれさせない

Last updated at Posted at 2021-12-15

はじめに

古いプロジェクトであればあるほど見つかるものがあります...
そう,「忘れ去られたTODOコメント」です...

main.go
// TODO: 後で共通化する

やろうとは思っていたものの工数が取れなかったり,単純に忘れてしまったりした結果,今日を迎えてしまったんでしょう.

そんな悲しいTODOコメントを生み出さないために,TODOコメントからGithubの
issueを自動生成するツールを作成しました.

(Githubのissueが作られても埋もれるだろ!という反論は受け付けます)

概要

main.go
// TODO: implement this

というTODOコメントがある場合,その.gitに登録されている1つ目のremoteに(多くの場合 origin)このようなissueが生成されます.

スクリーンショット 2021-12-06 23.17.07.jpg

同じTODOコメントで複数回issueを作成しないように,作成後は以下のようなコメントへ置き換えられます.

// TODO-#2{https://github.com/masibw/is-test/issues/2}: implement this

ちなみに,.gitの中は探索しないように設定されています.

使い方

Go言語で作られていますが,実行は言語を問わず行えます.ただし,現在は//から始まる行をコメントと判断しています.

Github アクセストークンの作成

https://github.com/settings/tokens

からrepoスコープを持つアクセストークンを作成してください.
スクリーンショット 2021-12-06 14.59.19.jpg

インストール

Goを使う場合配下のコマンドを実行して下さい.

go install github.com/masibw/gifc@latest

バイナリはreleasesからダウンロードすることもできます.

実行

issueを自動生成したい.gitがあるディレクトリで以下のコマンドを実行します.

GITHUB_TOKEN=your_token gifc

実装

フローチャートで表すとこんな感じです.
gifc.jpg

.gitからリモートリポジトリの情報を取得する

go-gitを使用して,.gitの情報を取得しています.

    repository, err := git.PlainOpen(".git")
    if err != nil {
        err = errors.Wrap(err, "failed to git PlainOpen")
        return nil, err
    }
    remotes, err := repository.Remotes()
    if err != nil {
        return nil, errors.Wrap(err, "failed to get Remotes")
    }

ファイルの走査

ファイルの一部を上書きしたいだけなのに,一旦ファイルの中身を消して全部上書きする形になるのは少し無駄な気もするんですが,どうしようもないんですかね?何か良い方法をおまちの方は教えてください:bow:
(もちろんPRを出してくれても嬉しいです:eyes:)

func (c *CommentUseCase) InspectFile(filePath string) (err error) {
    var file *os.File
    file, err = os.Open(filePath)
    defer func() {
        err = file.Close()
        if err != nil {
            err = errors.Wrap(err, "failed to Close")
        }
    }()

    if err != nil {
        err = errors.Wrap(err, "failed to open file")
        return
    }

    var bs []byte
    buf := bytes.NewBuffer(bs)
    fileScanner := bufio.NewScanner(file)

    for fileScanner.Scan() {
        line := fileScanner.Text()
        if isTodoComment(line) && notCreated(extractCommentContent(line)) {
            commentContent := extractCommentContent(line)
            todoContent := extractTodoContent(commentContent)
            var createdIssue *entity.Issue
            createdIssue, err = c.issueRepository.Create(entity.NewIssue(todoContent, todoContent), c.git)
            if err != nil {
                err = errors.Wrap(err, "failed to create issue")
                return
            }

            newComment := createdIssue.GenerateTodoCommentWithGithubInfo()
            err = writeLine(buf, newComment)
            if err != nil {
                err = errors.Wrap(err, "failed to writeLine")
                return
            }
        } else {
            err = writeLine(buf, line)
            if err != nil {
                err = errors.Wrap(err, "failed to writeLine")
                return
            }
        }
    }

    if err = fileScanner.Err(); err != nil {
        err = errors.Wrap(err, "error while reading file")
        return
    }

    err = os.WriteFile(filePath, buf.Bytes(), 0644)
    if err != nil {
        err = errors.Wrap(err, "failed to write file")
        return
    }

    return
}

issueの作成

go-githubを使ってgithubAPIを操作します.LabelやAssigneeも設定できるので,まだまだ便利に発展させられそうです.(gifcで自動生成したissueには同じラベルをつけるとか)

    ctx := context.Background()
    issueRequest := &github.IssueRequest{
        Title:     &issue.Title,
        Body:      &issue.Content,
        Labels:    nil,
        Assignee:  nil,
        State:     nil,
        Milestone: nil,
        Assignees: nil,
    }

    var gIssue *github.Issue
    gIssue, _, err = i.client.Issues.Create(ctx, git.Owner, git.Repository, issueRequest)
    if err != nil {
        err = errors.Wrap(err, "failed to create issues")
        return
    }

今後の展望

まだ実装できてないんですが,あったら自分も嬉しいなぁ〜という機能を書いておきます.

ignore機能

node_modulesなどの依存ファイルやテストコードなどのTODOからissueを作成して欲しくないファイルを登録できるようにしたいですね.

複数行のコメントに対応

main.go
/*
TODO: 並行処理する
各ファイルごとの処理は並行処理して,最終結果を待機する
*/

みたいな複数行のコメントがあった場合に,1行目をissueのタイトル・2行目以降を内容にするなど,複数行のコメントにも対応したいですね.

複数言語対応

現在は//をコメントの始まりとする言語にしか対応してませんが,#などがコメントを表す言語もあるので対応したいです.

dry-run機能の追加

どのようなissueが生成されるのか実行前に確認できた方が良いと思うので,dry-run機能も追加したいですね...

コメントとissueの紐付け

現在は コメント→issue はURLで辿れますが, issue→コメント は辿れません.issueがcloseされたらコメントも削除するとか,何かしらで実装できたら便利そうですが良い案は思いつきません...

さいごに

思いついたツールをガッと作ってしまったので,まだまだ改善点は多くあると思います.
issue作成,PR作成大歓迎ですので,是非 gifc をよろしくお願いします:tada:

9
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
1