Owen Rumney


Software Engineer


A few weeks ago I wrote tfsec-pr-commenter-action , this is a ready to go Github Action that you can drop into your Terraform code repository and have each PR checked for tfsec security issues.

If you don’t know anything about tfsec, you can learn more at https://tfsec.dev

The PR Commenter

It occurred to me shortly after adding it to some of our projects that the underlying commenter code could be used to comment using any static analysis tool with output.

Of course, the wrapping action code will be needed to un-marshall the analysis results but the creation of comments could be deferred to another library.

This is where go-github-pr-commenter comes in.

Usage

First, get the library;

go get github.com/owenrumney/go-github-pr-commenter/commenter

Then you need to import the library into your Github Action, or where ever it is being used.

import (
  "github.com/owenrumney/go-github-pr-commenter/commenter"
)

You will need a GITHUB_TOKEN to write the comments - if you’re using Github Actions you get one created for you when you activate Actions. If you are passing the GITHUB_TOKEN as a parameter to the Action called GITHUB_TOKEN, it is going to be available to your code as INPUT_GITHUB_TOKEN.

token := os.Getenv("INPUT_GITHUB_TOKEN")
if len(token) == 0 {
  return errors.New("Couldn't find the token")
}

Now that we have a token, we can create the Commenter

owner := "owenrumney"
repo := "go-github-pr-commenter"
prNo := 1


c, err := commenter.NewCommenter(token, owner, repo, prNo)
if err != nil {
    fmt.Println(err.Error())
}

We now have a commenter, on creation it checked that it had connectivity and that the PR exists so you would have an error if this wasn’t the case.

Let’s assume your static analysis results are in a slice call analysisResults - you can now iterate over them, and create the comments;

Lets say the AnalysisResult looks like this;

type AnalysisResult struct {
  Filepath  string
  Comment   string
  StartLine int
  EndLine   int
}

Now we iterate over the slice

for _, r := analysisResults {
  err = c.WriteMultiLineComment(r.Filepath, r.Comment, r.StartLine, r.EndLine)
}

If r.StartLine == r.EndLine the library will detect this and create a single line commit comment.

The error returned can be ignored under certain conditions. For example, if the same comment is being written again, this would return a commenter.CommentAlreadyWrittenError which can be dropped on the floor.