GitHubリポジトリ作成時の定形作業をTemplate Repositoryで省力化する

こんにちは。BASE BANK株式会社 Dev Division にて、 Software Developer をしている東口(@hgsgtk)です。Stay Homeで仕事していく中で、ちょっとした面倒事を解消するような小ネタが溜まってきたので、一つお届けします。

TL;DR

  • リポジトリ作成時には、毎回CIの設定・.editorconfig.gitignoreの配置、最低限のHello Worldコードの作成など、定形作業が存在する
  • 自分たち用のボイラープロジェクトを作成するCLIを用意するのも一つの手だが、気軽にサクッと出来る方法として、GitHubのTemplate Repositoryがある
  • Goプロジェクト作成時に実際に活用しているTemplate Repositoryをご紹介する

背景

BASE BANKでは、「YELL BANK(エールバンク)」というサービスの開発・運営を中心に、Goを用いてアプリケーション開発を行っています。
よくある面倒事として、新規にGoプロジェクトを作成する際に毎回作業するようなCI (Contenious Integration) の設定などがあります。 これは、Go言語に限った話ではありませんが、新規リポジトリを作成すると毎回脳死してコピペを行いがちなものがあります。 今回は、そんな面倒事をGitHubのTemplate Projectを用いてちょっとだけ省力化するお話です。

GitHubのTemplate Repositoryとは

Template Repositoryとは、「テンプレートリポジトリを作成する」で説明のある通り、既存のリポジトリをテンプレートにして同じディレクトリ構造・ブランチ・ファイルで新しいリポジトリを生成できるようになる機能です。

既存のリポジトリをテンプレートにして、自分や他の人が同じディレクトリ構造、ブランチ、およびファイルで新しいリポジトリを生成できるようにすることができます。

help.github.com

始め方は、非常にかんたんで、リポジトリの Settings にて、 Template repository にチェックを入れるだけです。

f:id:khigashigashi:20200623021116p:plain

こうして、チェックを入れると、新規リポジトリ作成時に、次のようにテンプレートが選択できるようになります。

f:id:khigashigashi:20200623021129p:plain

実際にテンプレートを選択すると、Template Repositoryの内容をコピーした形で新規リポジトリを作成できます。この機能を用いて、自分たちの定形作業をTemplate Repositoryに入れておくと、面倒事を少し解消することができます。

以下、具体的にどういう内容を入れているか、実際に活用しているGoプロジェクト用のTemplate Repositoryをご紹介します。

f:id:khigashigashi:20200623021642j:plain:w320

どういうことをしているか

BASE BANK Devでは、Goアプリケーションの新規リポジトリを作成することが多いのですが、次の内容をTemplate Repositoryに入れています。

  • CircleCIの設定
  • GitHub Actionの設定
  • Hello WorldなGoコード(go.modgo.sumと一緒に)
$ tree -L 2 -la
.
├── .circleci
│   └── config.yml
├── .editorconfig
├── .github
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows
├── .gitignore
├── .golangci.yml
├── README.md
└── app
    ├── Dockerfile
    ├── Makefile
    ├── go.mod
    ├── go.sum
    └── main.go

CircleCIの設定

GoコードにおけるCircleCIの自動Lint・テストは、次世代型イメージのcimg/goを使用した設定をしています。毎回コピペするのも面倒なので、レポジトリ作成時に生まれてくれると面倒事をさばく人生の時間が減って少しだけ幸せです。

version: 2.1

jobs:
  test-app:
    environment:
      TZ: "Asia/Tokyo"
      GO111MODULE: "on"

    docker:
      - image: cimg/go:1.14.4
        environment:
          GOCACHE: "/tmp/go/cache"
          TEST_RESULTS: /tmp/test-results

    steps:
      - checkout
      - run: mkdir -p $TEST_RESULTS
      - restore_cache:
          key: gopkg-{{ checksum "app/go.sum" }}
      - run:
          name: mod download
          command: |
            cd app
            go mod download
      - save_cache:
          key: gopkg-{{ checksum "app/go.sum" }}
          paths:
            - /home/circleci/go/pkg/mod
      - restore_cache:
          keys:
            - build-cache-{{ .Branch }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
      - run:
          name: install-gotools
          command: |
            cd app
            go get github.com/fzipp/gocyclo
      - run:
          name: build
          command: |
            cd app
            mkdir -p $GOCACHE
            go build -v
      - run:
          name: test
          command: |
            cd app
            gotestsum --junitfile ${TEST_RESULTS}/unit-tests.xml -- -p 6 -race -cover ./...
      - run:
          name: calcurate-cyclomatic-complexities
          command: |
            cd app
            gocyclo -avg $(find . -name "*.go" | grep -v _test)
      - save_cache:
          key: build-cache-{{ .Branch }}-{{ .Environment.CIRCLE_BUILD_NUM }}
          paths:
            - /tmp/go/cache
      - store_artifacts:
          path: /tmp/test-results
      - store_test_results:
          path: /tmp/test-results


workflows:
  version: 2

  test:
    jobs:
      - test-app

この設定内容自体については、同僚の@budougumi0617さんが「[Go]次世代イメージcimg/goとcircleci/go Orbsを使った2020年版CircleCIの環境構築」で解説しているのでそちらをご覧になってみてください。

budougumi0617.github.io

GitHub Actionの設定

.githubディレクトリ以下も、おまじないのように作るものが多い場所の一つでしょう。たとえば、PULL_REQUEST_TEMPLATE.md などは初手で作ることが多いです。それに加えて、GitHub Actionの設定もある程度共有できるものが多くなるため、それらもTemplate Repositoryという形で共有しています。

ReviewDogによるgolangci-lint実行

GoコードのLintにgolangci-lintを用いているのですが、その指摘内容をGitHubのコメントとして反映するため、ReviewDogを用いています。

具体的には、reviewdog/action-golangci-lintを活用しています。

github.com

実際に行っているのは、公式の解説どおりですが、以下のような設定を配置しています。

name: reviewdog
on: [pull_request]
jobs:
  golangci-lint:
    name: runner / golangci-lint
    runs-on: ubuntu-latest
    steps:
      - name: Check out code into the Go module directory
        uses: actions/checkout@v1
      - name: golangci-lint
        uses: reviewdog/action-golangci-lint@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          golangci_lint_flags: "--config=.golangci.yml ./..."

golangci-lint自体の設定もTemplate Repositoryに同梱しているため、レポジトリを作成すれば即座にgolangci-lintのチェック下に置かれます。

Hello WorldなGoコード

Go Modulesを用いる前提で Hello World コードを用意しています。主にAPIサービスを作る際に、app/ディレクトリ以下にアプリケーションコードを置くことが多いため、app/以下にmain.goを配置します。配置しているコードは、Go公式ブログの「Using Go Modules」に例示されているコードを微修正して置いています。

package main

import (
    "fmt"
    "rsc.io/quote"
)

var (
    revision = "default"
)

func main() {
    fmt.Println(hello())
}

func hello() string {
    return quote.Hello() + "by " + revision
}

また、テンプレ的に毎回用意するようなDockerfileも合わせて用意しています。

FROM golang:1.14.3-alpine3.11 as deploy-builder

WORKDIR /app

RUN apk add --no-cache git

ENV GO111MODULE=on

COPY . .
ARG REVISION="default"
RUN go build -ldflags "-X main.revision=${REVISION}"


FROM alpine as deploy

RUN apk add --no-cache tzdata && \
    cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    echo "Asia/Tokyo" > /etc/timezone

COPY --from=deploy-builder /app/app .

CMD ["./app"]

これらでどう嬉しくなったか

上記で紹介した以外にも脳死してコピペしていた .editorconfig なども最初から用意されるので、新規リポジトリ作成時の心のハードルが下がりました。

これからの課題としては、既存リポジトリの知見をTemplate Repositoryに反映していく流れや、デプロイフローについてのある程度の共有を図りたいと思っています。

最後に

Template Repositoryは、とくに特別な工数が発生するわけではない手軽な方法として、身近な面倒事を減らせる手になります。活用の仕方として参考になれば幸いです。