Help us understand the problem. What is going on with this article?

goの静的解析ツールをGithub Actionsのv2で動かしてみた

github actionsのバージョンが上がったので、自分が作ったアクションも書き換えてみました。

作ったもの

https://github.com/grandcolline/golang-github-actions

⬇こんな感じで通知される⬇
スクリーンショット.png

対応している静的解析ツールは以下のものです。

もの original
fmt https://golang.org/cmd/gofmt/
vet https://golang.org/cmd/vet/
imports https://godoc.org/golang.org/x/tools/cmd/goimports
lint https://godoc.org/golang.org/x/lint/golint
shadow https://godoc.org/golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
staticcheck https://godoc.org/honnef.co/go/tools/cmd/staticcheck
errcheck https://godoc.org/github.com/kisielk/errcheck
sec https://godoc.org/github.com/securego/gosec/cmd/gosec

READMEに書いてある通りなのですが、下記の感じでymlファイルを作ってもらえれば動きます。

.github/workflows/static.yml
name: static check
on: pull_request

jobs:
  fmt:
    name: Fmt
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - uses: grandcolline/golang-github-actions@v1.0.0
      with:
        run: fmt
        token: ${{ secrets.GITHUB_TOKEN }}

  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - uses: grandcolline/golang-github-actions@v1.0.0
      with:
        run: lint
        token: ${{ secrets.GITHUB_TOKEN }}

withで指定できる変数は以下の通りです。

変数名 デフォルト なに
run N/A 実行するコマンド(上の表から選ぶ)
directory . 静的解析を実行する場所の相対パス
comment true PRにコメントするか否か
token "" GitHub Token
flags "" コマンド実行時に追加するフラグ
ignore-defer false errcheck実行時に deferのエラーチェックを無視するか否か

いか、アクション作成する際にやったこと

アクションには、2種類のパターンがあるそうです。

今回はgoを使いたかったので、container actionsにしました。
公式のテンプレート通りに以下の構成にしました。

.
├── Dockerfile
├── LICENSE
├── README.md
├── action.yml
└── entrypoint.sh

Dockerfileは使いたいツールをインストールして、最終的にentrypoint.shを実行するだけのシンプルなもの。
やりたい処理などは、entrypoint.shにゴリゴリ書いていく。

Dockerfile
FROM golang::1.12.9

ENV GO111MODULE=on

RUN apt-get update && \
    apt-get -y install jq && \
    go get -u \
        github.com/kisielk/errcheck \
        golang.org/x/tools/cmd/goimports \
        golang.org/x/lint/golint \
        github.com/securego/gosec/cmd/gosec \
        golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow \
        honnef.co/go/tools/cmd/staticcheck

COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

action.yamlは、公式のドキュメントを参考に作成。

action.yml
name: "static analysis checker"
description: "static code analysis checker for golang"
author: "grandcolline"
inputs:
  run:
    description: "excute command. [errcheck/fmt/imports/lint/sec/shadow/staticcheck/vet]"
    required: true
  directory:
    description: "action wroking directory."
    default: "."
    required: false
  comment:
    description: "send comment to PR if true."
    default: true
    required: false
  token:
    description: "github token. this is require when comment is true."
    default: ""
    required: false
  flags:
    description: "add flags"
    default: ""
    required: false
  ignore-defer:
    description: "if this is true, do not detect 'defer' with error. This is only valid when run is errcheck."
    default: false
    required: false
runs:
  using: "docker"
  image: "Dockerfile"
  args:
    - ${{ inputs.run }}
    - ${{ inputs.directory }}
    - ${{ inputs.comment }}
    - ${{ inputs.token }}
    - ${{ inputs.flags }}
    - ${{ inputs.ignore-defer }}
branding:
  icon: "alert-triangle"
  color: "yellow"

args以外にもenvironmentでも渡せるので、どちらにするかは迷いどころだと思いました。どのようにかくのが綺麗なんだろう🤔
あと、Dockerのビルド時に渡すARGもここから指定できれば、golang自体のバージョン管理もアクション側でしなくて良くなりそうで良さそうだなぁと感じました。(ドキュメントを読み込めてないので、もしかしたらできるのかもしれない・・・)

最後に、entrypoint.shはシェルを書く。
長いので一部だけ書くとこんな感じ。全体はこちらから。

entrypoint.sh
#!/bin/sh
set -e

# ------------------------
#  Environments
# ------------------------
RUN=$1
WORKING_DIR=$2
SEND_COMMNET=$3
GITHUB_TOKEN=$4
FLAGS=$5
IGNORE_DEFER_ERR=$6

COMMENT=""
SUCCESS=0


# ------------------------
#  Functions
# ------------------------
send_comment() {
    PAYLOAD=$(echo '{}' | jq --arg body "${COMMENT}" '.body = $body')
    COMMENTS_URL=$(cat ${GITHUB_EVENT_PATH} | jq -r .pull_request.comments_url)
    curl -s -S -H "Authorization: token ${GITHUB_TOKEN}" --header "Content-Type: application/json" --data "${PAYLOAD}" "${COMMENTS_URL}" > /dev/null
}

mod_download() {
    if [ ! -e go.mod ]; then go mod init; fi
    go mod download
    if [ $? -ne 0 ]; then exit 1; fi
}

check_errcheck() {
    if [ "${IGNORE_DEFER_ERR}" = "true" ]; then
        IGNORE_COMMAND="| grep -v defer"
    fi

    set +e
    OUTPUT=$(sh -c "errcheck ${FLAGS} ./... ${IGNORE_COMMAND} $*" 2>&1)
    test -z "${OUTPUT}"
    SUCCESS=$?

    set -e
    if [ ${SUCCESS} -eq 0 ]; then
        return
    fi

    if [ "${SEND_COMMNET}" = "true" ]; then
        COMMENT="## ⚠ errcheck Failed
\`\`\`
${OUTPUT}
\`\`\`
"
    fi
}

# ------------------------
#  Main Flow
# ------------------------
cd ${GITHUB_WORKSPACE}/${WORKING_DIR}

case ${RUN} in
    "errcheck" )
        mod_download
        check_errcheck
        ;;
    * )
        echo "Invalid command"
        exit 1

esac

if [ ${SUCCESS} -ne 0 ]; then
    echo "Check Failed!!"
    echo ${COMMENT}
    if [ "${SEND_COMMNET}" = "true" ]; then
        send_comment
    fi
fi

exit ${SUCCESS}

最後に

アクションの書き方などのページがなくて辛かったですが、このあたりの記事がとても参考になりました。
感謝:pray:

https://qiita.com/homines22/items/0bc6c17e038b35fc8113
https://github.com/actions/container-template

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした