Instrumente Go & GitLab - cum să faceți integrarea continuă ca un șef

Fotografie de Todd Quackenbush pe Unsplash

La Pantomath, folosim GitLab pentru toate lucrările noastre de dezvoltare. Scopul acestei lucrări nu este de a prezenta GitLab și toate caracteristicile sale, ci de a introduce modul în care folosim aceste instrumente pentru a ne ușura viața.

Deci despre ce este vorba? Pentru a automatiza tot ceea ce este legat de proiectul dvs. de dezvoltare și vă permiteți să vă concentrați pe codul dvs. Vom acoperi scame, teste unitare, cursă de date, dezinfectant pentru memorie, acoperire de cod și construire.

Tot codul afișat în această postare este disponibil la https://gitlab.com/pantomath-io/demo-tools. Așadar, nu ezitați să obțineți depozitul și să utilizați etichetele pentru a naviga în el. Depozitul trebuie plasat în folderul src al $ GOPATH:

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

Instrumente du-te

Din fericire, Go vine cu o mulțime de instrumente utile, pentru a construi, testa și verifica codul tău. De fapt, totul este acolo. Vom adăuga doar instrumente suplimentare pentru a le lipi împreună. Dar înainte de a merge acolo, trebuie să le luăm unul câte unul și să vedem ce fac.

Lista pachetelor

Proiectul dvs. go este o colecție de pachete, așa cum este descris în documentul oficial. Majoritatea instrumentelor următoare vor fi alimentate cu aceste pachete și, astfel, prima comandă de care avem nevoie este o modalitate de a enumera pachetele. Sperăm, mergeți ne acoperă spatele cu subcomanda de listă (citiți manualul fin și această postare excelentă de la Dave Cheney):

$ go list. / ...

Rețineți că dorim să evităm aplicarea instrumentelor noastre pe resurse externe și să le restrângem la codul nostru. Deci trebuie să scăpăm de directoarele de vânzători:

$ go list. / ... | grep -v / furnizor /

Puf

Acesta este primul instrument pe care îl folosim pe cod: linterul. Rolul său este să te asiguri că codul respectă stilul codului. Acest lucru poate suna ca un instrument opțional sau cel puțin un „frumos-de-a avea”, dar ajută într-adevăr să păstrezi stilul coerent peste proiectul tău.

Această căptușeală nu face parte din sine, deci trebuie să o apucați și să o instalați de mână (a se vedea documentul oficial).

Utilizarea este destul de simplă: o executați doar pe pachetele codului dvs. (puteți indica și fișierele .go):

$ golint -set_exit_status $ (lista de accesare. / ... | grep -v / vendor /)

Rețineți opțiunea -set_exit_status. În mod implicit, golint tipărește doar problemele de stil și returnează (cu un cod return 0), deci CI nu consideră că ceva nu a mers corect. Dacă specificați -set_exit_status, codul de retur de la golint va fi diferit de 0 dacă se întâlnește vreo problemă de stil.

Test de unitate

Acestea sunt cele mai comune teste pe care le puteți rula pe codul dvs. Pentru fiecare fișier .go, trebuie să avem un fișier _test.go asociat care ține testele unității. Puteți rula testele pentru toate pachetele cu următoarea comandă:

$ go test-short $ (lista de plecare. / ... | grep -v / vendor /)

Cursa de date

Acesta este de obicei un subiect greu de acoperit, dar instrumentul go îl are în mod implicit (dar este disponibil doar pe linux / amd64, freebsd / amd64, darwin / amd64 și windows / amd64). Pentru mai multe informații despre cursa de date, consultați acest articol. Între timp, iată cum să-l executați:

$ go test -race -short $ (lista de accesare. / ... | grep -v / vendor /)

Dezinfectant pentru memorie

Clang are un detector frumos pentru citirile inițializate numite MemorySanitizer. Instrumentul de testare este suficient de bun pentru a interacționa cu acest modul Clang (de îndată ce sunteți pe gazda linux / amd64 și utilizați o versiune recentă a lui Clang / LLVM (> = 3.8.0). Această comandă este cum să o executați:

$ go test -msan -short $ (lista de accesare. / ... | grep -v / vendor /)

Acoperirea codului

Acesta este, de asemenea, un element obligatoriu pentru a evalua starea de sănătate a codului dvs. și pentru a vedea ce parte a codului se află în testele unității și ce parte nu. Rob Pike a scris o postare completă pe acest subiect.

Pentru a calcula raportul de acoperire a codului, trebuie să rulăm următorul script:

$ PKG_LIST = $ (lista de accesare. / ... | grep -v / vendor /)
$ pentru pachet în $ {PKG_LIST}; do
    go test -covermode = count -coverprofile "cover / $ {pachet ## * /}. cov" "$ pachet";
Terminat
$ tail -q -n +2 cover / *. cov >> cover / cover.cov
$ go tool cover -func = cover / cover.cov

Dacă dorim să obținem raportul de acoperire în format HTML, trebuie să adăugăm următoarea comandă:

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

Construi

Nu în ultimul rând, odată ce codul a fost testat complet, am putea dori să-l compilăm pentru a putea construi un binar funcțional.

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

Makefile

git tag: init-makefile

Fotografie de Matt Artz pe Unsplash

Acum avem toate instrumentele pe care le putem folosi în contextul integrării continue, le putem înfășura pe toate într-un Makefile și avem un mod constant de a le numi.

Scopul acestui document nu este prezentarea mărcii, ci vă puteți referi la documentația oficială pentru a afla mai multe despre el.

PROJECT_NAME: = "instrumente demo"
PKG: = "gitlab.com/pantomath-io/$(PROJECT_NAME)"
PKG_LIST: = $ (listă shell go $ {PKG} / ... | grep -v / vendor /)
GO_FILES: = $ (find find. -Name '* .go' | grep -v / vendor / | grep -v _test.go)
.PHONY: toate dep build test de acoperire curat, linte acoperire
toate: construiți
lint: ## Lint fișierele
 @golint -set_exit_status $ {PKG_LIST}
test: ## Executa unittests
 @go test -short $ {PKG_LIST}
cursa: dep ## Executa detectorul de curse de date
 @go test -race-short $ {PKG_LIST}
msan: dep ## Execută dezinfectant pentru memorie
 @go test -msan -short $ {PKG_LIST}
acoperire: ## Generați raportul global privind acoperirea codului
 ./tools/coverage.sh;
coverhtml: ## Generați raportul global de acoperire a codului în HTML
 ./tools/coverage.sh html;
dep: ## Obțineți dependențele
 @go get -v -d. / ...
build: dep ## Construiți fișierul binar
 @go build -i -v $ (PKG)
curat: ## Eliminați construcția anterioară
 @rm -f $ (PROJECT_NAME)
help: ## Afișați acest ecran de ajutor
 @grep -h -E '^ [a-zA-Z _-] +:. *? ##. * $$' $ (MAKEFILE_LIST) | awk 'BEGIN {FS = ":. *? ##"}; {printf "\ 033 [36m% -30s \ 033 [0m% s \ n", $$ 1, $$ 2} '

Ce avem, acum? O țintă pentru orice instrument prezentat anterior și încă 3 ținte pentru:

  • instalarea dependențelor (dep);
  • menținerea proiectului (curat);
  • ceva ajutor frumos și strălucitor.

Rețineți că a trebuit să creăm și un script pentru lucrările de acoperire a codului. Acest lucru se datorează faptului că implementarea buclelor peste fișiere dintr-un Makefile este o durere. Deci lucrarea este făcută într-un script bash, iar Makefile declanșează doar acest script.

Puteți încerca Makefile cu următoarele comenzi:

$ face ajutor
$ face scame
$ face acoperire

Integrare continuă

git tag: init-ci

Foto de Max Panamá pe Unsplash

Acum instrumentele sunt în vigoare și putem efectua diverse teste pe codul nostru, am dori să le automatizăm pe depozitul dvs. Din fericire, GitLab oferă conducte CI doar pentru acest lucru. Iar configurarea pentru aceasta este destul de simplă: tot ce creați este un fișier .gitlab-ci.yml la rădăcina depozitului.

Documentația completă a acestui fișier Yaml prezintă toate opțiunile, dar puteți începe cu acest .gitlab-ci.yml:

imagine: golang: 1.9
cache:
  căi:
    - / apt-cache
    - /go/src/github.com
    - /go/src/golang.org
    - /go/src/google.golang.org
    - /go/src/gopkg.in
etape:
  - Test
  - construi
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
  - face dep
unit_tests:
  etapa: test
  script:
    - faceți test
race_detector:
  etapa: test
  script:
    - face cursa
memory_sanitizer:
  etapa: test
  script:
    - face msan
code_coverage:
  etapa: test
  script:
    - faceți acoperire
code_coverage_report:
  etapa: test
  script:
    - faceți coverhtml
  numai:
  - maestru
lint_code:
  etapa: test
  script:
    - faceți scame
construi:
  etapă: construi
  script:
    - face

Dacă descompunem fișierul, iată câteva explicații despre conținutul acestuia:

  • Primul lucru este să alegeți ce imagine Docker va fi utilizată pentru a rula CI. Mergeți către Docker Hub pentru a alege imaginea potrivită pentru proiectul dvs.
  • Apoi, specificați unele foldere ale acestei imagini care trebuie să fie memorate în cache. Scopul aici este de a evita descărcarea aceluiași conținut de mai multe ori. Odată finalizată o lucrare, căile enumerate vor fi arhivate, iar următoarea lucrare va folosi aceeași arhivă.
  • Definiți diferitele etape care vă vor grupa joburile. În cazul nostru, avem două etape (care urmează să fie procesate în acea ordine): testare și construire. Am putea avea alte etape, cum ar fi implementarea.
  • Secțiunea before_script definește comenzile care vor fi rulate în containerul Docker chiar înainte ca lucrarea să fie efectiv finalizată. În contextul nostru, comenzile trebuie doar să copieze sau să conecteze depozitul implementat în $ GOPATH și să instaleze dependențe.
  • Apoi veniți lucrările efective, folosind țintele Makefile. Rețineți cazul special pentru code_coverage_report în care execuția este limitată la sucursala principală (nu dorim să actualizăm raportul de acoperire a codului de la sucursalele de funcții, de exemplu).

Pe măsură ce comitem / împingem fișierul .gitlab-ci.yml din depozit, CI este declanșat automat. Și conducta eșuează. Cum se face?

Jobul lint_code eșuează deoarece nu poate găsi binarul golint:

$ face scame
make: golint: Comanda nu a fost găsită
Makefile: 11: rețeta pentru „lint” țintă a eșuat
make: *** [lint] Eroarea 127

Deci, actualizați Makefile pentru a instala golint ca parte a țintei dep.

Jobul memory_sanitizer eșuează deoarece gcc se plânge:

$ face msan
# runtime / cgo
gcc: eroare: argument nerecunoscut la -fsanitize = opțiune: 'memorie'
Makefile: 20: rețeta pentru „msan” țintă a eșuat
make: *** [msan] Eroarea 2

Amintiți-vă însă că trebuie să utilizăm Clang / LLVM> = 3.8.0 pentru a ne bucura de opțiunea -msan din comanda de testare.

Avem 2 opțiuni aici:

  • fie instalăm Clang în job (folosind înainte_script);
  • sau folosim o imagine Docker cu Clang instalată implicit.

Prima opțiune este drăguță, dar asta presupune realizarea acestei configurații pentru fiecare lucrare. Aceasta va fi atât de lungă, ar trebui să o facem o dată pentru totdeauna. Așa că preferăm a doua opțiune, care este o modalitate bună de a juca cu GitLab Registry.

git tag: use-own-docker

Trebuie să creăm un Dockerfile pentru container (ca de obicei: citiți documentația oficială pentru mai multe opțiuni despre acesta):

# Imagine de bază: https://hub.docker.com/_/golang/
DE la golang: 1.9
MAINTAINER Julien Andrieux 
# Instalați golint
ENV GOPATH / go
ENV PATH $ {GOPATH} / bin: $ PATH
RUN accesați -u github.com/golang/lint/golint
# Adăugați cheie aptă pentru depozitul LLVM
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
# Adăugați repositorul apt LLVM
RUN ecou "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch-5.0 main" | tee -a /etc/apt/sources.list
# Instalați clang din depozitul LLVM
RUN apt-get update && apt-get install -y --no-install-recomandă \
    clang-5.0 \
    && apt-get clean \
    && rm -rf / var / lib / apt / liste / * / tmp / * / var / tmp / *
# Setați Clang ca CC implicit
ENV set_clang /etc/profile.d/set-clang-cc.sh
RUN ecou "export CC = clang-5.0" | tee -a $ {set_clang} && chmod a + x $ {set_clang}

Containerul construit din acest Dockerfile se va baza pe o imagine golang: 1.9 (cea la care se face referire în fișierul .gitlab-ci.yml).

În timp ce suntem la el, instalăm golint în container, așa că îl avem disponibil. Apoi urmăm modul oficial de instalare a Clang 5.0 din depozitul LLVM.

Acum avem Dockerfile în loc, trebuie să construim imaginea containerului și să-l punem la dispoziție pentru 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

Prima comandă vă conectează la Registrul GitLab. Apoi construiți imaginea containerului descrisă în Dockerfile. Și în final, îl împingeți în Registrul GitLab.

Aruncați o privire la Registrul pentru depozitul dvs., veți vedea imaginea dvs. gata de utilizare. Pentru a avea CI-ul folosind imaginea dvs., trebuie doar să actualizați fișierul .gitlab-ci.yml:

imagine: golang: 1.9

devine

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

Un ultim detaliu: trebuie să spuneți CI-ului să folosească compilatorul corespunzător (adică variabila de mediu CC), deci adăugăm inițializarea variabilei în fișierul .gitlab-ci.yml:

export CC = clang-5.0

Odată ce modificarea este făcută, următorul angajament va declanșa conducta, care acum funcționează:

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

insignele

git tag: init-badges

Fotografie de Jakob Owens pe Unsplash

Acum, instrumentele sunt în vigoare, fiecare angajament va lansa o suită de teste și probabil doriți să o arătați, iar acest lucru este legitim :) Cel mai bun mod de a face acest lucru este să folosiți ecusoane, iar cel mai bun loc pentru acesta este fișierul README.

Editează-l și adaugă cele 4 insigne următoare:

  • Build Status: starea ultimei conducte de pe ramura principală:
[! [Build Status] (https://gitlab.com/pantomath-io/demo-tools/badges/master/build.svg)] (https://gitlab.com/pantomath-io/demo-tools/commits /maestru)
  • Raport de acoperire: procentul de cod acoperit de teste
[! [Raport de acoperire] (https://gitlab.com/pantomath-io/demo-tools/badges/master/coverage.svg)] (https://gitlab.com/pantomath-io/demo-tools/commits /maestru)
  • Accesați cardul de raport:
[! [Go Report Card] (https://goreportcard.com/badge/gitlab.com/pantomath-io/demo-tools)] (https://goreportcard.com/report/gitlab.com/pantomath-io/ demo-unelte)
  • Licență:
[! [Licență MIT] (https://img.shields.io/badge/License-MIT-brightgreen.svg)] (https://img.shields.io/badge/License-MIT-brightgreen.svg)

Raportul de acoperire are nevoie de o configurație specială. Trebuie să spuneți GitLab cum să obțineți informațiile respective, având în vedere că există un job în CI care îl afișează atunci când rulează.
Există o configurație care să ofere GitLab un regexp, utilizat în ieșirea oricărei lucrări. Dacă regexp se potrivește, GitLab consideră că meciul este rezultatul acoperirii codului.

Așa că mergeți la Setări> CI / CD din depozitul dvs., derulați în jos la setarea de analiză a acoperirii de test din secțiunea Setări generale ale conductelor și folosiți următorul regexp:

totalul: \ s + \ (declarații \) \ s + (\ d + \ d + \%.)

Ești gata! Mergeți la prezentarea generală a depozitului dvs. și uitați-vă la README:

Concluzie

Ce urmeaza? Probabil mai multe teste în CI. Puteți, de asemenea, să vă uitați la CD-ul (implementare continuă) pentru a automatiza implementarea compilărilor. Documentația poate fi făcută folosind GoDoc. Rețineți că generați un raport de acoperire cu code_coverage_report, dar nu îl utilizați în CI. Puteți face ca lucrarea să copieze fișierul HTML pe un server web, folosind scp (consultați această documentație despre cum să utilizați tastele SSH).

Multe mulțumiri lui Charles Francoise care a scris această lucrare și https://gitlab.com/pantomath-io/demo-tools.

În prezent lucrăm la Pantomath. Pantomath este o soluție de monitorizare modernă, open-source, construită pentru performanțe, care asigură punerea la distanță pe toate nivelurile companiei. Bunăstarea infrastructurii dvs. este afacerea tuturor. Țineți pasul cu proiectul