GoツールとGitLab —上司のように継続的インテグレーションを行う方法

UnsplashのTodd Quackenbushによる写真

Pantomathでは、すべての開発作業にGitLabを使用しています。このホワイトペーパーの目的は、GitLabとそのすべての機能を紹介することではなく、これらのツールを使用して生活を楽にする方法を紹介することです。

それで、それは何についてですか?開発プロジェクトに関連するすべてを自動化し、コードに集中できるようにします。リント、単体テスト、データ競合、メモリサニタイザー、コードカバレッジ、ビルドについて説明します。

この投稿に示されているすべてのコードは、https://gitlab.com/pantomath-io/demo-toolsで入手できます。リポジトリを自由に取得し、タグを使用してリポジトリ内を移動してください。リポジトリは、$ GOPATHのsrcフォルダーに配置する必要があります。

$ go get -v -d gitlab.com/pantomath-io/demo-tools
$ cd $ GOPATH / src / gitlab.com / pantomath-io / demo-tools

移動ツール

幸い、Goには、コードをビルド、テスト、およびチェックするための便利なツールが多数付属しています。実際、すべてがそこにあります。追加のツールを追加して、それらを結合します。しかし、そこに行く前に、私たちはそれらを一つずつ取り上げ、彼らが何をするかを見る必要があります。

パッケージリスト

goプロジェクトは、公式ドキュメントで説明されているように、パッケージのコレクションです。以下のツールのほとんどにはこれらのパッケージが提供されるため、最初に必要なコマンドはパッケージをリストする方法です。うまくいけば、listサブコマンドで背中をカバーしてください(Dave Cheneyのすばらしいマニュアルとこの素晴らしい投稿を読んでください):

$ go list。/ ...

外部リソースにツールを適用するのを避け、コードに制限することに注意してください。したがって、ベンダーディレクトリを削除する必要があります。

$ go list。/ ... | grep -v / vendor /

糸くず

これは、コードで使用する最初のツールであるリンターです。その役割は、コードがコードスタイルを尊重することを確認することです。これはオプションのツールのように聞こえるかもしれませんが、少なくとも「必要なもの」に聞こえるかもしれませんが、プロジェクト全体で一貫したスタイルを維持するのに役立ちます。

このリンターは、それ自体がgoの一部ではないため、手に持ってインストールする必要があります(公式ドキュメントを参照)。

使用方法は非常に簡単です。コードのパッケージで実行するだけです(.goファイルを指定することもできます)。

$ golint -set_exit_status $(go list。/ ... | grep -v / vendor /)

-set_exit_statusオプションに注意してください。デフォルトでは、golintはスタイルの問題のみを出力し、リターンする(リターンコード0)ので、CIは何かが間違っているとは考えません。 -set_exit_statusを指定すると、スタイルの問題が発生した場合、golintからの戻りコードは0とは異なります。

単体テスト

これらは、コードで実行できる最も一般的なテストです。 .goファイルごとに、ユニットテストを保持する_test.goファイルを関連付ける必要があります。次のコマンドを使用して、すべてのパッケージのテストを実行できます。

$ go test -short $(go list。/ ... | grep -v / vendor /)

データ競合

通常、これはカバーするのが難しいテーマですが、goツールにはデフォルトで含まれています(ただし、linux / amd64、freebsd / amd64、darwin / amd64、windows / amd64でのみ使用可能です)。データ競合の詳細については、この記事を参照してください。一方、ここに実行方法があります:

$ go test -race -short $(go list。/ ... | grep -v / vendor /)

メモリーサニタイザー

Clangには、MemorySanitizerと呼ばれる初期化されていない読み取り用の優れた検出器があります。 goテストツールは、このClangモジュールと対話するのに十分なほど親切です(linux / amd64ホスト上で、最新バージョンのClang / LLVM(> = 3.8.0)を使用するとすぐに、このコマンドを実行する方法です)。

$ go test -msan -short $(go list。/ ... | grep -v / vendor /)

コードカバレッジ

これは、コードの健全性を評価し、コードのどの部分が単体テスト下にあり、どの部分がそうでないかを確認するためにも必要です。ロブパイクは、まさにその主題に関する完全な投稿を書きました。

コードカバレッジ率を計算するには、次のスクリプトを実行する必要があります。

$ PKG_LIST = $(go list。/ ... | grep -v / vendor /)
$ {PKG_LIST}のパッケージの場合;行う
    go test -covermode = count -coverprofile "cover / $ {package ## * /}。cov" "$ package";
やった
$ tail -q -n +2 cover / *。cov >> cover / coverage.cov
$ go tool cover -func = cover / coverage.cov

カバレッジレポートをHTML形式で取得する場合は、次のコマンドを追加する必要があります。

$ go tool cover -html = cover / coverage.cov -o coverage.html

構築する

最後に大事なことを言い忘れましたが、コードが完全にテストされたら、それをコンパイルして作業バイナリをビルドできるようにします。

$ go build -i -v gitlab.com/pantomath-io/demo-tools

メイクファイル

gitタグ:init-makefile

UnsplashのMatt Artzによる写真

これで、継続的インテグレーションのコンテキストで使用できるすべてのツールが揃ったので、それらをすべてMakefileでラップし、一貫した方法で呼び出すことができます。

このドキュメントの目的はmakeを提示することではありませんが、公式ドキュメントを参照して詳細を確認できます。

PROJECT_NAME:= "デモツール"
PKG:= "gitlab.com/pantomath-io/$(PROJECT_NAME)"
PKG_LIST:= $(シェルゴーリスト$ {PKG} / ... | grep -v / vendor /)
GO_FILES:= $(shell find。-name '* .go' | grep -v / vendor / | grep -v _test.go)
.PHONY:すべてのdepビルドクリーンテストカバレッジcoverhtml lint
すべて:ビルド
lint:##ファイルのリント
 @golint -set_exit_status $ {PKG_LIST}
テスト:## unittestsを実行します
 @goテスト-short $ {PKG_LIST}
race:dep ##データ競合検出器の実行
 @go test -race -short $ {PKG_LIST}
msan:dep ##メモリサニタイザーを実行する
 @go test -msan -short $ {PKG_LIST}
カバレッジ:##グローバルコードカバレッジレポートを生成
 ./tools/coverage.sh;
coverhtml:## HTMLでグローバルコードカバレッジレポートを生成する
 ./tools/coverage.sh html;
dep:##依存関係を取得する
 @go get -v -d。/ ...
build:dep ##バイナリファイルをビルドします
 @go build -i -v $(PKG)
clean:##前のビルドを削除
 @rm -f $(PROJECT_NAME)
help:##このヘルプ画面を表示する
 @grep -h -E '^ [a-zA-Z _-] +:。*?##。* $$' $(MAKEFILE_LIST)| awk 'BEGIN {FS = ":。*?##"}; {printf "\ 033 [36m%-30s \ 033 [0m%s \ n"、$$ 1、$$ 2} '

今、何がありますか?以前に提示されたツールの1つのターゲット、および次の3つのターゲット:

  • 依存関係のインストール(dep);
  • プロジェクトのハウスキーピング(クリーン);
  • いくつかの素敵で光沢のあるヘルプ(ヘルプ)。

また、コードカバレッジ作業用のスクリプトを作成する必要がありました。これは、Makefile内のファイルに対するループの実装が苦痛だからです。したがって、作業はbashスクリプトで行われ、Makefileはこのスクリプトのみをトリガーします。

次のコマンドでMakefileを試すことができます。

$助けて
$糸くずを作る
$報道する

継続的インテグレーション

gitタグ:init-ci

UnsplashのMaxPanamáによる写真

これでツールが準備できました。コードでさまざまなテストを実行できます。リポジトリでこれらを自動化したいと思います。幸いなことに、GitLabはこのためにCIパイプラインを提供しています。このセットアップは非常に簡単です。作成するのは、リポジトリのルートにある.gitlab-ci.ymlファイルだけです。

このYamlファイルの完全なドキュメントにはすべてのオプションが記載されていますが、この.gitlab-ci.ymlから始めることができます。

画像:golang:1.9
キャッシュ:
  パス:
    -/ apt-cache
    -/go/src/github.com
    -/go/src/golang.org
    -/go/src/google.golang.org
    -/go/src/gopkg.in
段階:
  -テスト
  -ビルド
before_script:
  -mkdir -p /go/src/gitlab.com/pantomath-io / go / src / _ / builds
  -cp -r $ CI_PROJECT_DIR /go/src/gitlab.com/pantomath-io/pantomath
  -ln -s /go/src/gitlab.com/pantomath-io / go / src / _ / builds / pantomath-io
  -デップする
unit_tests:
  段階:テスト
  スクリプト:
    -テストする
race_detector:
  段階:テスト
  スクリプト:
    -レースをする
memory_sanitizer:
  段階:テスト
  スクリプト:
    -msanを作る
code_coverage:
  段階:テスト
  スクリプト:
    -報道する
code_coverage_report:
  段階:テスト
  スクリプト:
    -coverhtmlを作成
  のみ:
  - マスター
lint_code:
  段階:テスト
  スクリプト:
    -糸くずを作る
ビルド:
  ステージ:ビルド
  スクリプト:
    -作る

ファイルを分解する場合、その内容に関する説明を次に示します。

  • 最初に行うことは、CIの実行に使用するDockerイメージを選択することです。 Docker Hubに移動して、プロジェクトに適した画像を選択します。
  • 次に、キャッシュするこのイメージのいくつかのフォルダーを指定します。ここでの目標は、同じコンテンツを何度もダウンロードしないようにすることです。ジョブが完了すると、リストされたパスがアーカイブされ、次のジョブは同じアーカイブを使用します。
  • ジョブをグループ化するさまざまなステージを定義します。このケースでは、テストとビルドの2つのステージ(この順序で処理される)があります。展開など、他の段階を設定することもできます。
  • before_scriptセクションは、ジョブが実際に完了する直前にDockerコンテナで実行するコマンドを定義します。このコンテキストでは、コマンドは$ GOPATHにデプロイされたリポジトリをコピーまたはリンクし、依存関係をインストールするだけです。
  • 次に、Makefileターゲットを使用して、実際のジョブを作成します。 code_coverage_reportの特別なケースに注意してください。実行はmasterブランチに制限されています(たとえば、機能ブランチからのコードカバレッジレポートを更新したくない)。

リポジトリで.gitlab-ci.ymlファイルをコミット/プッシュすると、CIが自動的にトリガーされます。そして、パイプラインが失敗します。どうして?

golintバイナリが見つからないため、lint_codeジョブは失敗します。

$糸くずを作る
make:golint:コマンドが見つかりません
Makefile:11:ターゲット 'lint'のレシピが失敗しました
make:*** [lint]エラー127

そのため、Makefileを更新して、delinターゲットの一部としてgolintをインストールします。

gccが不平を言っているため、memory_sanitizerジョブは失敗します。

$ make msan
#runtime / cgo
gcc:エラー:-fsanitize =オプションへの認識されない引数: 'memory'
Makefile:20:ターゲット「msan」のレシピが失敗しました
make:*** [msan]エラー2

ただし、go testコマンドで-msanオプションを使用するには、Clang / LLVM> = 3.8.0を使用する必要があることに注意してください。

ここには2つのオプションがあります。

  • ジョブでClangをセットアップする(before_scriptを使用);
  • または、デフォルトでClangがインストールされたDockerイメージを使用します。

最初のオプションは素晴らしいですが、それはすべての単一のジョブに対してこのセットアップを行うことを意味します。これは非常に長くなるので、一度だけ実行する必要があります。そのため、GitLab Registryで遊ぶのに適した2番目のオプションをお勧めします。

gitタグ:use-own-docker

コンテナ用のDockerfileを作成する必要があります(いつものように、公式ドキュメントでオプションの詳細を確認してください):

#基本画像:https://hub.docker.com/_/golang/
golang:1.9から
メンテナンスジュリアン・アンドリュー
#golintをインストールする
ENV GOPATH / go
ENV PATH $ {GOPATH} / bin:$ PATH
RUN go get -u github.com/golang/lint/golint
#LLVMリポジトリのaptキーを追加
RUN wget -O-https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add-
#LLVM aptリポジトリを追加
RUN echo "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch-5.0 main" | tee -a /etc/apt/sources.list
#LLVMリポジトリからclangをインストール
apt-get update && apt-get install -y --no-install-recommends \を実行します
    clang-5.0 \
    && apt-get clean \
    && rm -rf / var / lib / apt / lists / * / tmp / * / var / tmp / *
#ClangをデフォルトCCとして設定
ENV set_clang /etc/profile.d/set-clang-cc.sh
RUN echo "export CC = clang-5.0" | tee -a $ {set_clang} && chmod a + x $ {set_clang}

このDockerfileから構築されるコンテナーは、golang:1.9イメージ(.gitlab-ci.ymlファイルで参照されるイメージ)に基づいています。

作業中にgolintをコンテナにインストールするので、利用可能にします。次に、LLVMリポジトリからClang 5.0をインストールする公式の方法に従います。

これでDockerfileが準備できました。コンテナーイメージをビルドし、GitLabで使用できるようにする必要があります。

$ docker login registry.gitlab.com
$ docker build -t registry.gitlab.com/pantomath-io/demo-tools。
$ docker push registry.gitlab.com/pantomath-io/demo-tools

最初のコマンドは、GitLab Registryに接続します。次に、Dockerfileに記述されているコンテナーイメージをビルドします。最後に、GitLab Registryにプッシュします。

リポジトリのレジストリを見てください。使用可能な状態の画像が表示されます。また、イメージを使用してCIを作成するには、.gitlab-ci.ymlファイルを更新するだけです。

画像:golang:1.9

になる

画像:registry.gitlab.com/pantomath-io/demo-tools:latest

最後の詳細:適切なコンパイラー(つまり、CC環境変数)を使用するようCIに指示する必要があるため、変数初期化を.gitlab-ci.ymlファイルに追加します。

エクスポートCC = clang-5.0

変更が完了すると、次のコミットによってパイプラインがトリガーされ、パイプラインが機能するようになります。

https://gitlab.com/pantomath-io/demo-tools/pipelines/13497136

バッジ

gitタグ:init-badges

UnsplashのJakob Owensによる写真

これでツールが配置され、すべてのコミットでテストスイートが起動します。おそらくそれを表示する必要があります。これは正当な方法です。

それを編集して、次の4つのバッジを追加します。

  • ビルドステータス:masterブランチの最後のパイプラインのステータス:
[![ビルドステータス](https://gitlab.com/pantomath-io/demo-tools/badges/master/build.svg)](https://gitlab.com/pantomath-io/demo-tools/commits /マスター)
  • カバレッジレポート:テストでカバーされるコードの割合
[![カバレッジレポート](https://gitlab.com/pantomath-io/demo-tools/badges/master/coverage.svg)](https://gitlab.com/pantomath-io/demo-tools/commits /マスター)
  • Goレポートカード:
[![Go Report Card](https://goreportcard.com/badge/gitlab.com/pantomath-io/demo-tools)](https://goreportcard.com/report/gitlab.com/pantomath-io/デモツール)
  • ライセンス:
[![License MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://img.shields.io/badge/License-MIT-brightgreen.svg)

カバレッジレポートには特別な設定が必要です。 CIには実行時に情報を表示するジョブがあることを考慮して、GitLabにその情報を取得する方法を伝える必要があります。
任意のジョブの出力で使用される正規表現をGitLabに提供する構成があります。正規表現が一致する場合、GitLabは一致をコードカバレッジ結果と見なします。

リポジトリの[設定]> [CI / CD]に進み、[一般的なパイプライン設定]セクションの[テストカバレッジ解析]設定まで下にスクロールし、次の正規表現を使用します。

合計:\ s + \(statements \)\ s +(\ d +。\ d + \%)

準備完了です!リポジトリの概要に進み、READMEをご覧ください。

結論

次は何ですか?おそらくあなたのCIでより多くのテスト。また、CD(連続展開)を見て、ビルドの展開を自動化することもできます。ドキュメントはGoDocを使用して作成できます。 code_coverage_reportでカバレッジレポートを生成しますが、CIでは使用しないことに注意してください。 scpを使用して、ジョブでHTMLファイルをWebサーバーにコピーできます(SSHキーの使用方法については、このドキュメントを参照してください)。

この論文とhttps://gitlab.com/pantomath-io/demo-toolsを共同執筆したCharles Francoiseに感謝します。

現在、Pantomathに取り組んでいます。 Pantomathは、パフォーマンスのために構築された最新のオープンソース監視ソリューションであり、企業のあらゆるレベルのギャップを埋めます。インフラストラクチャの健全性はすべての人のビジネスです。プロジェクトについていく