Go Tools & GitLab - wie man Continuous Integration wie ein Boss macht

Foto von Todd Quackenbush auf Unsplash

Bei Pantomath verwenden wir GitLab für alle unsere Entwicklungsarbeiten. Der Zweck dieses Dokuments ist nicht, GitLab und all seine Funktionen vorzustellen, sondern vorzustellen, wie wir diese Tools verwenden, um unser Leben zu erleichtern.

Worum geht es also? Automatisieren Sie alles, was mit Ihrem Entwicklungsprojekt zusammenhängt, und konzentrieren Sie sich auf Ihren Code. Wir decken die Bereiche Flusen, Unit-Tests, Datenrennen, Speicherbereinigung, Codeabdeckung und Build ab.

Der gesamte Code in diesem Beitrag ist unter https://gitlab.com/pantomath-io/demo-tools verfügbar. Holen Sie sich also das Repository und navigieren Sie mit den Tags darin. Das Repository sollte im src-Ordner Ihres $ GOPATH abgelegt werden:

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

Gehen Sie Werkzeuge

Zum Glück enthält Go viele nützliche Tools, mit denen Sie Ihren Code erstellen, testen und überprüfen können. Tatsächlich ist alles da. Wir fügen nur zusätzliche Werkzeuge hinzu, um sie zusammenzukleben. Aber bevor wir dorthin gehen, müssen wir sie eins nach dem anderen nehmen und sehen, was sie tun.

Paketliste

Ihr go-Projekt ist eine Sammlung von Paketen, wie im offiziellen Dokument beschrieben. Die meisten der folgenden Tools werden mit diesen Paketen gespeist, und daher ist der erste Befehl, den wir benötigen, eine Möglichkeit, die Pakete aufzulisten. Hoffentlich deckt go unseren Rücken mit dem Unterbefehl list ab (lesen Sie das feine Handbuch und diesen ausgezeichneten Beitrag von Dave Cheney):

$ go list. / ...

Beachten Sie, dass wir vermeiden möchten, unsere Tools auf externe Ressourcen anzuwenden, und sie auf unseren Code beschränken möchten. Also müssen wir die Herstellerverzeichnisse loswerden:

$ go Liste. / ... | grep -v / vendor /

Fussel

Dies ist das allererste Tool, das wir für den Code verwenden: den Linter. Seine Aufgabe ist es, sicherzustellen, dass der Code den Codestil respektiert. Dies mag sich nach einem optionalen Tool anhören oder zumindest nach einem „nice to have“, aber es hilft wirklich dabei, einen konsistenten Stil für Ihr Projekt beizubehalten.

Dieser Linter ist nicht Teil von go per se. Sie müssen ihn also greifen und von Hand installieren (siehe offizielles Dokument).

Die Verwendung ist recht einfach: Sie führen es einfach auf den Paketen Ihres Codes aus (Sie können auch auf die .go-Dateien verweisen):

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

Beachten Sie die Option -set_exit_status. Standardmäßig druckt golint nur die Stilprobleme und gibt sie zurück (mit dem Rückkehrcode 0), sodass das CI niemals davon ausgeht, dass etwas schief gelaufen ist. Wenn Sie -set_exit_status angeben, unterscheidet sich der Rückkehrcode von golint von 0, wenn ein Stilproblem auftritt.

Gerätetest

Dies sind die häufigsten Tests, die Sie für Ihren Code ausführen können. Für jede .go-Datei muss eine _test.go-Datei vorhanden sein, die die Komponententests enthält. Sie können die Tests für alle Pakete mit dem folgenden Befehl ausführen:

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

Datenrennen

Dies ist normalerweise ein schwieriges Thema, aber das go-Tool hat es standardmäßig (aber nur verfügbar unter Linux / amd64, freebsd / amd64, darwin / amd64 und windows / amd64). Weitere Informationen zu Data Race finden Sie in diesem Artikel. In der Zwischenzeit erfahren Sie, wie es ausgeführt wird:

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

Speicher-Desinfektionsprogramm

Clang hat einen schönen Detektor für nicht initialisierte Lesevorgänge namens MemorySanitizer. Das Go-Test-Tool ist so freundlich, mit diesem Clang-Modul zu interagieren (sobald Sie auf einem Linux / amd64-Host arbeiten und eine neuere Version von Clang / LLVM (> = 3.8.0) verwenden).

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

Code-Abdeckung

Dies ist auch ein Muss, um den Zustand Ihres Codes zu bewerten und festzustellen, welcher Teil des Codes Unit-Tests unterzogen wird und welcher nicht. Rob Pike hat einen vollständigen Beitrag zu diesem Thema geschrieben.

Um den Codeabdeckungsgrad zu berechnen, müssen Sie das folgende Skript ausführen:

$ PKG_LIST = $ (go list. / ... | grep -v / vendor /)
$ für Paket in $ {PKG_LIST}; tun
    test -covermode = count -coverprofile "cover / $ {package ## * /}. cov" "$ package";
erledigt
$ tail -q -n +2 cover / *. cov >> cover / coverage.cov
$ go tool cover -func = cover / coverage.cov

Wenn wir den Abdeckungsbericht im HTML-Format erhalten möchten, müssen wir den folgenden Befehl hinzufügen:

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

Bauen

Zu guter Letzt möchten wir den Code, nachdem er vollständig getestet wurde, kompilieren, um sicherzugehen, dass wir eine funktionierende Binärdatei erstellen können.

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

Makefile

Git-Tag: Init-Makefile

Foto von Matt Artz auf Unsplash

Jetzt verfügen wir über alle Tools, die wir im Kontext der kontinuierlichen Integration verwenden können, können sie alle in ein Makefile packen und auf einheitliche Weise aufrufen.

Der Zweck dieses Dokuments ist nicht, make vorzustellen, aber Sie können sich auf die offizielle Dokumentation beziehen, um mehr darüber zu erfahren.

PROJECT_NAME: = "Demo-Tools"
PKG: = "gitlab.com/pantomath-io/$(PROJECT_NAME)"
PKG_LIST: = $ (Shell-Go-Liste $ {PKG} / ... | grep -v / vendor /)
GO_FILES: = $ (Shell find. -Name '* .go' | grep -v / vendor / | grep -v _test.go)
.PHONY: alle dep Build sauber Testabdeckung Coverhtml Fussel
alle: bauen
Lint: ## Lint die Dateien
 @golint -set_exit_status $ {PKG_LIST}
test: ## Unittests ausführen
 @go test -short $ {PKG_LIST}
race: dep ## Datenrennen-Detektor ausführen
 @go test -race -short $ {PKG_LIST}
msan: dep ## Speicherbereinigung ausführen
 @go test -msan -short $ {PKG_LIST}
Abdeckung: ## Generieren Sie einen Bericht zur globalen Codeabdeckung
 ./tools/coverage.sh;
coverhtml: ## Generiert einen Bericht zur globalen Codeabdeckung in HTML
 ./tools/coverage.sh html;
dep: ## Liefert die Abhängigkeiten
 @go get -v -d. / ...
build: dep ## Erstellt die Binärdatei
 @go build -i -v $ (PKG)
sauber: ## Vorherige Version entfernen
 @rm -f $ (PROJECT_NAME)
help: ## Zeigt diesen Hilfebildschirm an
 @grep -h -E '^ [a-zA-Z _-] +:. *? ##. * $$' $ (MAKEFILE_LIST) | awk 'BEGIN {FS = ":. *? ##"}; {printf "\ 033 [36m% -30s \ 033 [0m% s \ n", $$ 1, $$ 2} "

Was haben wir jetzt? Ein Ziel für ein zuvor vorgestelltes Tool und 3 weitere Ziele für:

  • Installation von Abhängigkeiten (dep);
  • Housekeeping des Projekts (sauber);
  • etwas nette und glänzende Hilfe (help).

Beachten Sie, dass wir auch ein Skript für die Code-Coverage-Arbeit erstellen mussten. Dies liegt daran, dass das Implementieren von Schleifen über Dateien in einem Makefile mühsam ist. Die Arbeit wird also in einem Bash-Skript ausgeführt, und das Makefile löst nur dieses Skript aus.

Sie können das Makefile mit den folgenden Befehlen ausprobieren:

$ Hilfe machen
Machen Sie Fusseln
$ Abdeckung machen

Kontinuierliche Integration

Git-Tag: Init-Ci

Foto von Max Panamá auf Unsplash

Jetzt sind die Tools installiert und wir können verschiedene Tests für unseren Code ausführen. Diese möchten wir in Ihrem Repository automatisieren. Zum Glück bietet GitLab dafür CI-Pipelines an. Und das Setup dafür ist ziemlich einfach: Alles, was Sie erstellen, ist eine .gitlab-ci.yml-Datei im Stammverzeichnis des Repositorys.

Die vollständige Dokumentation zu dieser Yaml-Datei enthält alle Optionen. Sie können jedoch mit dieser .gitlab-ci.yml beginnen:

Bild: Golang: 1.9
Zwischenspeicher:
  Pfade:
    - / apt-cache
    - /go/src/github.com
    - /go/src/golang.org
    - /go/src/google.golang.org
    - /go/src/gopkg.in
Stufen:
  - Prüfung
  - bauen
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
  - machen dep
unit_tests:
  Bühne: Test
  Skript:
    - Test machen
race_detector:
  Bühne: Test
  Skript:
    - Rennen machen
memory_sanitizer:
  Bühne: Test
  Skript:
    - Msan machen
code_coverage:
  Bühne: Test
  Skript:
    - Berichterstattung machen
code_coverage_report:
  Bühne: Test
  Skript:
    - Coverhtml machen
  nur:
  - Meister
lint_code:
  Bühne: Test
  Skript:
    - Flusen machen
bauen:
  Bühne: bauen
  Skript:
    - machen

Wenn Sie die Datei aufschlüsseln, finden Sie hier einige Erklärungen zum Inhalt:

  • Als Erstes müssen Sie auswählen, mit welchem ​​Docker-Image das CI ausgeführt werden soll. Gehen Sie zum Docker Hub, um das richtige Bild für Ihr Projekt auszuwählen.
  • Anschließend geben Sie einige Ordner dieses Bildes an, die zwischengespeichert werden sollen. Das Ziel hierbei ist, dass derselbe Inhalt nicht mehrmals heruntergeladen wird. Sobald ein Auftrag abgeschlossen ist, werden die aufgelisteten Pfade archiviert, und der nächste Auftrag verwendet dasselbe Archiv.
  • Sie definieren die verschiedenen Phasen, in denen Ihre Jobs gruppiert werden. In unserem Fall haben wir zwei Phasen (die in dieser Reihenfolge abgearbeitet werden müssen): Testen und Erstellen. Wir könnten andere Phasen haben, wie zum Beispiel die Bereitstellung.
  • Der Abschnitt before_script definiert die Befehle, die im Docker-Container ausgeführt werden sollen, bevor der Auftrag tatsächlich ausgeführt wird. In unserem Kontext kopieren oder verknüpfen die Befehle lediglich das in $ GOPATH implementierte Repository und installieren Abhängigkeiten.
  • Dann kommen die eigentlichen Jobs mit den Makefile-Zielen. Beachten Sie den Sonderfall für code_coverage_report, bei dem die Ausführung auf den Hauptzweig beschränkt ist (wir möchten den Code-Coverage-Bericht beispielsweise nicht über Feature-Zweige aktualisieren).

Wenn wir die Datei .gitlab-ci.yml im Repository festschreiben / pushen, wird das CI automatisch ausgelöst. Und die Pipeline fällt aus. Woher?

Der Job "lint_code" schlägt fehl, weil er die Golint-Binärdatei nicht finden kann:

Machen Sie Fusseln
make: golint: Befehl nicht gefunden
Makefile: 11: Rezept für Ziel 'Fussel' fehlgeschlagen
make: *** [lint] Fehler 127

Aktualisieren Sie also Ihr Makefile, um golint als Teil des Dep-Ziels zu installieren.

Der memory_sanitizer-Job schlägt fehl, weil sich gcc beschwert:

$ make msan
# Laufzeit / cgo
gcc: error: nicht erkanntes Argument für -fsanitize = option: 'memory'
Makefile: 20: Rezept für Ziel 'msan' fehlgeschlagen
make: *** [msan] Fehler 2

Denken Sie jedoch daran, dass Sie Clang / LLVM> = 3.8.0 verwenden müssen, um die Option -msan im Befehl go test zu verwenden.

Wir haben hier zwei Möglichkeiten:

  • Entweder richten wir Clang im Job ein (unter Verwendung von before_script).
  • oder wir verwenden ein Docker-Image mit standardmäßig installiertem Clang.

Die erste Option ist nett, aber das bedeutet, dass diese Einrichtung für jeden einzelnen Job durchgeführt werden muss. Das wird so lange dauern, wir sollten es ein für alle Mal tun. Daher bevorzugen wir die zweite Option, die eine gute Möglichkeit ist, mit GitLab Registry zu spielen.

Git-Tag: Use-Own-Docker

Wir müssen eine Docker-Datei für den Container erstellen (wie üblich: Lesen Sie die offizielle Dokumentation, um weitere Optionen zu erhalten):

# Basis-Image: https://hub.docker.com/_/golang/
FROM golang: 1.9
MAINTAINER Julien Andrieux 
# Installieren Sie golint
ENV GOPATH / go
ENV PATH $ {GOPATH} / bin: $ PATH
RUN get -u github.com/golang/lint/golint
# Fügen Sie einen passenden Schlüssel für das LLVM-Repository hinzu
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
# LLVM-Apt-Repository hinzufügen
RUN echo "deb http://apt.llvm.org/stretch/llvm-toolchain-stretch-5.0 main" | tee -a /etc/apt/sources.list
# Installieren Sie clang aus dem LLVM-Repository
RUN 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 als Standard-CC festlegen
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}

Der aus dieser Docker-Datei erstellte Container basiert auf dem golang: 1.9-Image (das in der .gitlab-ci.yml-Datei angegeben ist).

Während wir gerade dabei sind, setzen wir Golint in den Container ein, damit wir es zur Verfügung haben. Dann folgen wir der offiziellen Methode zur Installation von Clang 5.0 aus dem LLVM-Repository.

Nachdem wir das Dockerfile installiert haben, müssen wir das Container-Image erstellen und es für GitLab verfügbar machen:

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

Der erste Befehl verbindet Sie mit der GitLab Registry. Anschließend erstellen Sie das im Dockerfile beschriebene Container-Image. Und schließlich schieben Sie es in die GitLab-Registry.

Sehen Sie sich die Registrierung für Ihr Repository an. Ihr Image wird angezeigt und kann verwendet werden. Damit das CI Ihr Image verwendet, müssen Sie nur die Datei .gitlab-ci.yml aktualisieren:

Bild: Golang: 1.9

wird

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

Ein letztes Detail: Sie müssen dem CI mitteilen, dass der richtige Compiler (d. H. Die CC-Umgebungsvariable) verwendet werden soll. Daher fügen wir die Variableninitialisierung in die Datei .gitlab-ci.yml ein:

export CC = clang-5.0

Sobald die Änderung abgeschlossen ist, löst das nächste Festschreiben die Pipeline aus, die jetzt funktioniert:

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

Abzeichen

Git-Tag: Init-Abzeichen

Foto von Jakob Owens auf Unsplash

Nachdem die Tools installiert sind, wird bei jedem Commit eine Testsuite gestartet, die Sie wahrscheinlich anzeigen möchten, und das ist legitim.

Bearbeiten Sie es und fügen Sie die 4 folgenden Abzeichen hinzu:

  • Erstellungsstatus: Der Status der letzten Pipeline in der Hauptverzweigung:
[! [Build Status] (https://gitlab.com/pantomath-io/demo-tools/badges/master/build.svg)] (https://gitlab.com/pantomath-io/demo-tools/commits) /Meister)
  • Abdeckungsbericht: Der Prozentsatz des Codes, der durch Tests abgedeckt wird
[! [Berichterstattung] (https://gitlab.com/pantomath-io/demo-tools/badges/master/coverage.svg)] (https://gitlab.com/pantomath-io/demo-tools/commits /Meister)
  • Go Report Card:
[! [Go Report Card] (https://goreportcard.com/badge/gitlab.com/pantomath-io/demo-tools)] (https://goreportcard.com/report/gitlab.com/pantomath-io/) Demo-Tools)
  • Lizenz:
[! [License MIT] (https://img.shields.io/badge/License-MIT-brightgreen.svg)] (https://img.shields.io/badge/License-MIT-brightgreen.svg)

Der Abdeckungsbericht benötigt eine spezielle Konfiguration. Sie müssen GitLab mitteilen, wie diese Informationen abgerufen werden sollen, da das CI einen Auftrag enthält, der diese Informationen bei der Ausführung anzeigt.
Es gibt eine Konfiguration, um GitLab mit einem regulären Ausdruck zu versehen, der in jeder Jobausgabe verwendet wird. Wenn der reguläre Ausdruck übereinstimmt, betrachtet GitLab die Übereinstimmung als Ergebnis der Codeabdeckung.

Gehen Sie also in Ihrem Repository zu Einstellungen> CI / CD, scrollen Sie nach unten zur Einstellung Test Coverage Parsing im Abschnitt Allgemeine Einstellungen für Pipelines und verwenden Sie den folgenden regulären Ausdruck:

Gesamt: \ s + \ (Anweisungen \) \ s + (\ d +. \ d + \%)

Sie sind fertig! Gehen Sie zur Übersicht Ihres Repository und sehen Sie sich Ihre README-Datei an:

Fazit

Was kommt als nächstes? Wahrscheinlich mehr Tests in Ihrem CI. Sie können sich auch die CD (Continuous Deployment) ansehen, um die Bereitstellung Ihrer Builds zu automatisieren. Die Dokumentation kann mit GoDoc erfolgen. Beachten Sie, dass Sie einen Abdeckungsbericht mit dem code_coverage_report erstellen, ihn jedoch nicht im CI verwenden. Sie können den Job veranlassen, die HTML-Datei mit scp auf einen Webserver zu kopieren (Informationen zur Verwendung von SSH-Schlüsseln finden Sie in dieser Dokumentation).

Vielen Dank an Charles Francoise, der dieses Paper und https://gitlab.com/pantomath-io/demo-tools mitgeschrieben hat.

Wir arbeiten derzeit an Pantomath. Pantomath ist eine moderne Open-Source-Überwachungslösung, die auf Leistung ausgelegt ist und die Lücken auf allen Ebenen Ihres Unternehmens schließt. Das Wohl Ihrer Infrastruktur geht alle an. Bleiben Sie mit dem Projekt auf dem Laufenden