Go tools & GitLab - как да направите непрекъсната интеграция като шеф

Снимка на Тод Куакенбуш на Unsplash

В Pantomath използваме GitLab за цялата ни работа по разработване. Целта на този документ не е да представи GitLab и всички негови характеристики, а да въведе как използваме тези инструменти, за да облекчим живота си.

И така, за какво става въпрос? За да автоматизирате всичко, което е свързано с вашия проект за разработка, и да ви позволи да се съсредоточите върху вашия код. Ще покрием козирката, тестовете на единиците, състезанието за данни, дезинфекцията на паметта, покритието на кода и изграждането.

Целият код, показан в тази публикация, е достъпен на https://gitlab.com/pantomath-io/demo-tools. Така че не се колебайте да вземете хранилището и да използвате маркерите, за да се движите в него. Хранилището трябва да бъде поставено в src папката на вашия $ GOPATH:

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

Go инструменти

За щастие, Go идва с много полезни инструменти за изграждане, тестване и проверка на вашия код. Всъщност всичко е там. Просто ще добавим допълнителни инструменти, за да ги залепите заедно. Но преди да отидем там, трябва да ги вземем един по един и да видим какво правят.

Списък с опаковки

Вашият проект е колекция от пакети, както е описано в официалния документ. Повечето от следните инструменти ще бъдат захранвани с тези пакети и по този начин първата команда, от която се нуждаем, е начин да изброим пакетите. Да се ​​надяваме, че обхваща гърба ни със подкоманда на списъка (прочетете прекрасното ръководство и този отличен пост от Дейв Чейни):

$ go list. / ...

Обърнете внимание, че искаме да избегнем прилагането на нашите инструменти върху външни ресурси и да го ограничим до нашия код. Затова трябва да се отървем от директориите на доставчиците:

$ go list. / ... | grep -v / продавач /

марля

Това е първият инструмент, който използваме в кода: линтера. Нейната роля е да гарантира, че кодът спазва стила на кода. Това може да звучи като незадължителен инструмент или поне „приятен за ползване“, но наистина помага да поддържате последователен стил на вашия проект.

Този лайнер не е част от go per se, така че трябва да го вземете и да го инсталирате на ръка (вижте официалния документ).

Използването е доста просто: просто го стартирате върху пакетите на вашия код (можете също да насочите .go файловете):

$ golint -set_exit_status $ (отидете в списъка. / ... | grep -v / vendor /)

Обърнете внимание на опцията -set_exit_status. По подразбиране golint отпечатва само стиловите проблеми и се връща (с 0 връщащ код), така че CI никога не смята, че нещо не е наред. Ако зададете -set_exit_status, връщащият се код от golint ще бъде различен от 0, ако се среща някакъв проблем със стила.

Единичен тест

Това са най-често срещаните тестове, които можете да стартирате на вашия код. За всеки .go файл трябва да имаме свързан _test.go файл, съдържащ тестовете на единицата. Можете да стартирате тестовете за всички пакети със следната команда:

$ go тест -short $ (иди списък. / ... | 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 тест -msan -short $ (иди списък. / ... | grep -v / vendor /)

Кодово покритие

Това също трябва да оцените здравето на вашия код и да видите каква част от кода е под единица тестове и каква част не. Роб Пайк написа пълен пост по тази тема.

За да изчислим коефициента на покритие на кода, трябва да стартираме следния скрипт:

$ PKG_LIST = $ (отидете в списъка. / ... | grep -v / vendor /)
$ за пакет в $ {PKG_LIST}; правя
    go test -covermode = count -coverprofile "cover / $ {package ## * /}. cov" "$ package";
Свършен
$ опашка -q -n +2 капак / *. cov >> капак / покритие.cov
$ go tool cover -func = cover / покритие.cov

Ако искаме да получим отчета за покритие във формат HTML, трябва да добавим следната команда:

$ go tool cover -html = cover / cover.cov -o покритие.html

Изграждане

Не на последно място, след като кодът е напълно тестван, може да искаме да го компилираме, за да можем да изградим работещ двоичен файл.

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

Makefile

git tag: init-makefile

Снимка на Мат Artz на Unsplash

Сега имаме всички инструменти, които можем да използваме в контекста на непрекъсната интеграция, можем да ги увием в Makefile и да имаме последователен начин да ги извикваме.

Целта на този документ не е да представи марката, но можете да се обърнете към официалната документация, за да научите повече за нея.

PROJECT_NAME: = "демо-инструменти"
PKG: = "gitlab.com/pantomath-io/$(PROJECT_NAME)"
PKG_LIST: = $ (shell go list list $ {PKG} / ... | grep -v / vendor /)
GO_FILES: = $ (shell find. -Name '* .go' | grep -v / vendor / | grep -v _test.go)
.PHONY: всички dep изграждат чист тест покритие coverhtml власинка
всички: изграждане
lint: ## Облечете файловете
 @golint -set_exit_status $ {PKG_LIST}
тест: ## Изпълнете единични тестове
 @go test -short $ {PKG_LIST}
състезание: dep ## Пуснете детектор за състезание с данни
 @go test -race -short $ {PKG_LIST}
msan: dep ## Стартирайте дезинфектант на паметта
 @go тест -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)
чист: ## Премахване на предишната компилация
 @rm -f $ (PROJECT_NAME)
помощ: ## Показване на този помощен екран
 @grep -h -E '^ [a-zA-Z _-] +:. *? ##. * $$' $ (MAKEFILE_LIST) | awk 'НАЧАЛИ {FS = ":. *? ##"}; {printf "\ 033 [36m% -30s \ 033 [0m% s \ n", $$ 1, $$ 2} '

Какво имаме сега? Една цел за всеки представен преди това инструмент и още 3 цели за:

  • инсталиране на зависимости (dep);
  • поддържане на проекта (чисто);
  • някаква хубава и лъскава помощ (помощ).

Обърнете внимание, че ние също трябваше да създадем скрипт за работа с покритие на кода. Това е така, защото прилагането на цикли над файлове в Makefile е болка. Така работата се извършва по баш скрипт, а Makefile само задейства този скрипт.

Можете да опитате Makefile със следните команди:

$ направи помощ
$ make lint
$ направи покритие

Непрекъсната интеграция

git tag: init-ci

Снимка на Макс Панама на Unsplash

Сега инструментите са налице и можем да стартираме различни тестове на нашия код, бихме искали да ги автоматизираме във вашето хранилище. За щастие, GitLab предлага CI тръбопроводи точно за това. И настройката за това е доста проста: всичко, което създавате, е .gitlab-ci.yml файл в корена на хранилището.

Пълната документация на този файл на Yaml представя всички опции, но можете да започнете с този .gitlab-ci.yml:

изображение: golang: 1.9
кеша:
  пътеки:
    - / apt-кеш
    - /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 / _ / изгражда
  - 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
  - направи dep
unit_tests:
  етап: тест
  скрипт:
    - направи тест
race_detector:
  етап: тест
  скрипт:
    - правя състезание
memory_sanitizer:
  етап: тест
  скрипт:
    - направи msan
code_coverage:
  етап: тест
  скрипт:
    - направи покритие
code_coverage_report:
  етап: тест
  скрипт:
    направете coverhtml -
  само:
  - майстор
lint_code:
  етап: тест
  скрипт:
    - направи мъх
изграждане на:
  етап: изграждане
  скрипт:
    - правя

Ако разбиете файла, ето някои обяснения за съдържанието му:

  • Първото нещо е да изберете какъв образ на Docker ще се използва за стартиране на CI. Насочете се към Docker Hub, за да изберете правилното изображение за вашия проект.
  • След това посочвате някои папки на това изображение, които да се кешират. Целта тук е да се избегне изтеглянето на едно и също съдържание няколко пъти. След като задачата е завършена, изброените пътища ще бъдат архивирани и следващата задача ще използва същия архив.
  • Вие определяте различните етапи, които ще групират вашите работни места. В нашия случай имаме два етапа (да бъдат обработени в този ред): тестване и изграждане. Можем да имаме и други етапи, като например разполагане.
  • Секцията before_script определя командите, които да се изпълняват в контейнера на Docker точно преди задачата да бъде действително свършена. В нашия контекст командите просто копират или свързват хранилището, разположено в $ GOPATH, и инсталират зависимости.
  • След това идват действителните задачи, като използвате целите на Makefile. Обърнете внимание на специалния случай за code_coverage_report, когато изпълнението е ограничено до главния клон (не искаме например да актуализираме отчета за покритие на кода от клонове на функции).

Докато извършваме / натискаме .gitlab-ci.yml файла в хранилището, CI се задейства автоматично. И тръбопроводът се проваля. Как така?

Задачата lint_code се проваля, защото не може да намери двоичния код на golint:

$ make lint
марка: golint: Командата не е намерена
Makefile: 11: рецептата за целта „власинка“ не бе успешна
make: *** [lint] Грешка 127

Така че, актуализирайте своя Makefile, за да инсталирате golint като част от dep target.

Заданието memory_sanitizer се проваля, защото gcc се оплаква:

$ make msan
# време на изпълнение / cgo
gcc: грешка: неразпознат аргумент до -fsanitize = опция: 'памет'
Makefile: 20: рецептата за целта „msan“ не е успешна
направи: *** [msan] Грешка 2

Но не забравяйте, че трябва да използваме Clang / LLVM> = 3.8.0, за да се насладим на опцията -msan в командата go test.

Тук имаме 2 възможности:

  • или инсталираме Clang в заданието (използвайки before_script);
  • или използваме изображение на Докер с инсталиран по подразбиране Clang.

Първата опция е хубава, но това предполага да се направи тази настройка за всяка отделна работа. Това ще бъде толкова дълго, ние трябва да го направим веднъж завинаги. Затова предпочитаме втория вариант, който е добър начин да играете с GitLab Registry.

git tag: use-own-docker

Трябва да създадем Dockerfile за контейнера (както обикновено: прочетете официалната документация за повече опции за него):

# Основно изображение: https://hub.docker.com/_/golang/
ОТ golang: 1.9
ОСЪЖДА Жулиен Андрие 
# Инсталирайте golint
ENV GOPATH / отивам
ENV PATH $ {GOPATH} / bin: $ PATH
RUN go get -u github.com/golang/lint/golint
# Добавяне на подходящ ключ за LLVM хранилище
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-ключ добавяне -
# Добави LLVM apt хранилище
RUN echo "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch-5.0 main" | tee -a /etc/apt/sources.list
# Инсталиране на кланг от LLVM хранилище
RUN apt-get update && apt-get install -y --no-install-препоръчва \
    кланг-5.0 \
    && apt - изчисти се \
    && rm -rf / var / lib / apt / списъци / * / tmp / * / var / tmp / *
# Задайте Clang като CC по подразбиране
ENV set_clang /etc/profile.d/set-clang-cc.sh
RUN ехо "експортиране на CC = clang-5.0" | tee -a $ {set_clang} && chmod a + x $ {set_clang}

Контейнерът, изграден от този Dockerfile, ще се основава на изображение на golang: 1.9 (този, който е посочен във файла .gitlab-ci.yml).

Докато сме в това, ние инсталираме golint в контейнера, така че да го имаме на разположение. След това следваме официалния начин за инсталиране на Clang 5.0 от LLVM хранилище.

Сега имаме Dockerfile на място, трябва да изградим изображението на контейнера и да го направим достъпно за GitLab:

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

Първата команда ви свързва с регистъра на GitLab. След това изграждате изображението на контейнера, описано в Dockerfile. И накрая, вие го натискате към регистъра на GitLab.

Погледнете Регистъра за вашето хранилище, ще видите вашето изображение, готово за използване. И за да имате CI, използвайки вашето изображение, просто трябва да актуализирате .gitlab-ci.yml файла:

изображение: golang: 1.9

става

изображение: register.gitlab.com/pantomath-io/demo-tools:latest

Последна подробност: трябва да кажете на CI да използва правилния компилатор (т.е. променливата на средата CC), така че добавяме инициализацията на променливата във файла .gitlab-ci.yml:

износ CC = кланг-5.0

След като модификацията бъде извършена, следващият ангажимент ще задейства тръбопровода, който сега работи:

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

Значките

git tag: init-значки

Снимка на Jakob Owens на Unsplash

Сега инструментите са налице, всеки ангажимент ще стартира тестов пакет и вероятно искате да го покажете, и това е законно :) Най-добрият начин да направите това е да използвате значки, а най-доброто място за него е файлът README.

Редактирайте го и добавете 4 следните значки:

  • Състояние на изграждане: състоянието на последния тръбопровод в основния клон:
[! [Състояние на изграждане] (https://gitlab.com/pantomath-io/demo-tools/badges/master/build.svg)] (https://gitlab.com/pantomath-io/demo-tools/commissions / магистър)
  • Доклад за покритие: процентът на кода, обхванат от тестовете
[! [Доклад за покритие] (https://gitlab.com/pantomath-io/demo-tools/badges/master/coverage.svg)] (https://gitlab.com/pantomath-io/demo-tools/commissions / магистър)
  • Отидете на отчетна карта:
[! [Go Report Card] (https://goreportcard.com/badge/gitlab.com/pantomath-io/demo-tools)] (https://goreportcard.com/report/gitlab.com/pantomath-io/ демо-инструменти)
  • Разрешително:
[! [Лиценз MIT] (https://img.shields.io/badge/License-MIT-brightgreen.svg)] (https://img.shields.io/badge/License-MIT-brightgreen.svg)

Отчетът за покритие се нуждае от специална конфигурация. Трябва да кажете на GitLab как да получите тази информация, като имате предвид, че в CI има работа, която я показва, когато се изпълнява.
Има конфигурация за предоставяне на GitLab с регулярно показване, използвано в изхода на всяка работа. Ако regexp съвпада, GitLab счита мача за резултат от покритието на кода.

Така че отидете на Настройки> CI / CD във вашето хранилище, превъртете надолу до настройката Тестване на анализа на покритието в секцията Общи настройки на тръбопроводите и използвайте следното regexp:

общо: \ S + \ (извлечения \) \ S + (\ г + \ г + \%).

Готов си! Отидете до прегледа на вашето хранилище и погледнете README:

заключение

Какво следва? Вероятно повече тестове при вас CI. Можете също така да разгледате CD (непрекъснато внедряване), за да автоматизирате разполагането на вашите компилации. Документацията може да се направи с помощта на GoDoc. Обърнете внимание, че генерирате отчет за покритие с code_coverage_report, но не го използвайте в потребителския индекс. Можете да накарате заданието да копира HTML файла на уеб сървър, като използвате scp (вижте тази документация за това как да използвате SSH ключовете).

Много благодаря на Чарлз Франсоаз, който написа този документ и https://gitlab.com/pantomath-io/demo-tools.

В момента работим върху Pantomath. Pantomath е модерно решение за мониторинг с отворен код, създадено за ефективност, което преодолява пропуските във всички нива на вашата компания. Благосъстоянието на вашата инфраструктура е работа на всеки. Продължавайте с проекта