[Go, GitHub] Публикация Go приложения в GitHub
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Пост представляет собой контрольный список (checklist) и его реализацию при публикации Go приложения на Github'е.TLDR:
- Makefile как входная точка для выполнения основных действий
- Линтеры и тесты как инструменты повышающие качество кода
- Dockerfile как способ распространения приложения
- Github Actions как возможность автоматической сборки и выкладки приложения при новых изменениях
- Goreleaser как инструмент для публикации релизов и пакетов
Результатом должно быть опубликованное приложение с настроенными инструментами которые позволяют легко сопровождать приложение в процессе его существования. В качестве реального примера я буду рассматривать утилиту pgcenter.Disclaimer: Приведенный список не являются абсолютной истинной и является лишь субъективным списком вещей к которым я пришел в процессе публикации приложении. Список может дополняться и изменяться. Все это одно большое ИМХО, если у вас есть альтернативный взгляд или вы уверены/знаете что какие-то вещи можно сделать еще лучше, обязательно дайте знать в комментах.Будем двигаться от простого к сложному. В случае встречи имен файлов, все они взяты относительно корня проекта где находится код приложения.MakefileMakefile хранит в себе служебные сценарии которые приходится часто выполнять при разработке приложения:
- выполнение линтеров и тестов
- сборка приложения
- запуск приложения
- сборка артефактов типа пакетов, docker образов и т.п.
- публикация артефактов в сторонние репозитории
- выполнение операций относительно внешних систем, например SQL миграции если речь идет о корпоративных приложениях В Makefile складываются рутинные операции выполнять которые приходится регулярно. Основная цель Makefile это помочь вам не держать в голове все нужные команды, параметры и аргументы, а собрать и их в одном месте и при необходимости выполнить их и получить результат. Позже Makefile также будет основным сценарием для запуска этих же рутинных процедур в CI/CD. Минимальная версия Makefile может выглядеть так:
PROGRAM_NAME = pgcenter
COMMIT=$(shell git rev-parse --short HEAD)
BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
TAG=$(shell git describe --tags |cut -d- -f1)
LDFLAGS = -ldflags "-X main.gitTag=${TAG} -X main.gitCommit=${COMMIT} -X main.gitBranch=${BRANCH}"
.PHONY: help clean dep build install uninstall
.DEFAULT_GOAL := help
help: ## Display this help screen.
@echo "Makefile available targets:"
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " * \033[36m%-15s\033[0m %s\n", $$1, $$2}'
dep: ## Download the dependencies.
go mod download
build: dep ## Build pgcenter executable.
mkdir -p ./bin
CGO_ENABLED=0 GOOS=linux GOARCH=${GOARCH} go build ${LDFLAGS} -o bin/${PROGRAM_NAME} ./cmd
clean: ## Clean build directory.
rm -f ./bin/${PROGRAM_NAME}
rmdir ./bin
Давайте разберем важные моменты в приведенном Makefile.
- В начале файла указываем служебные переменные которые потребуются дальше. Переменных немного, называние программы и информация из Git которая используется при сборке. В частности коммит, тег и ветка которые через сборщика пробрасываются в код приложения и используются для формирования версии программы. При таком подходе версия всегда берется из Git и не нужно хранить строку с версией в коде приложения, помнить о ней, своевременно обновлять. Отмечу что проброс переменных не автоматическая магия, предполагается что в Git используются теги и также есть соответствующие правки в коде для приема Git переменных. Например 1 и 2.
- Следующий интересный момент это пункт help, он реализует справку для нашего Makefile - обратите внимание на комментарии начинающиеся с двойной решетки после названий пунктов. Эти комментарии как раз и используются в качестве справки если вызвать make без аргументов или явно make help.
- Следующие пункты являются базовыми для жизненного цикла Go приложения: загрузка зависимостей, сборка и очистка каталога где хранится собранная программа.
При желании список пунктов можно дополнить, что я и буду делать дальше по ходу текста.Линтеры и тестыСледующий шаг добавление линтеров. Основная задача линтеров проверять код на предмет "странных" конструкций которые не соответствуют принятым стилям программирования или даже хуже, могут быть неоптимальными и приводить к каким-либо ошибкам. Наличие линтеров позволяют поддерживать хорошее качество кода, ориентироваться на правильный стиль написания кода принятый в языке. Использование линтеров необязательно, но крайне желательно. В go есть масса разных линтеров, я пришел пока к использованию golangci-lint и gosec. Первый включает в себя большой набор разных линтеров (включены при этом не все), второй является линтером с уклоном в соблюдение правил информационной безопасности.Выполнение линтеров также регулярная задача, поэтому также добавляем их в Makefile
lint: dep ## Lint the source files
golangci-lint run --timeout 5m -E golint
gosec -quiet ./...
В приведенном случае для выполнения golangci-lint выставлен таймаут, через флаг -E включаются дополнительные линтеры. Выполнение gosec особо ничем не примечательно, просто рекурсивный обход каталогов.Очевидно что golangci-lint и gosec должны быть установлены в системе. Их установка проста, описывать тут не буду.Также код сопровождается тестами, добавим и их выполнение тоже.
test: dep ## Run tests
go test -race -p 1 -timeout 300s -coverprofile=.test_coverage.txt ./... && \
go tool cover -func=.test_coverage.txt | tail -n1 | awk '{print "Total test coverage: " $$3}'
@rm .test_coverage.txt
Команда запускает тесты, формирует файл с покрытием кода этими тестами и печатает результат покрытия.DockerfileСледующим этапом является Dockerfile, который позволит собирать Docker образы нашего приложения.
# stage 1: build
FROM golang:1.15 as build
LABEL stage=intermediate
WORKDIR /app
COPY . .
RUN make build
# stage 2: scratch
FROM scratch as scratch
COPY --from=build /app/bin/pgcenter /bin/pgcenter
CMD ["pgcenter"]
Сборка образа состоит из двух этапов, сборка приложения и его копирование в пустой образ. Таким двухэтапным образом можно упаковывать приложения которые не требуют внешних зависимостей типа библиотек, сертификатов, других программ или чего-то аналогичного. Помимо сборки Docker образа потребуется место откуда другие пользователи смогут его забрать, например этим местом может быть Docker Hub. Для размещения там образа потребуется аккаунт и реквизиты (логин/пароль).Сборка и публикация образа также регулярная операция, поэтому добавляем команды в Makefile.
docker-build: ## Build docker image
docker build -t lesovsky/pgcenter:${TAG} .
docker image prune --force --filter label=stage=intermediate
docker-push: ## Push docker image to registry
docker push lesovsky/pgcenter:${TAG}
Обратите внимание, что используется переменная TAG которая определяется в начале Makefile.Github ActionsТеперь когда у нас есть способ для сборки приложения (Makefile) и публикации (Dockerfile), нам нужен механизм который поможет автоматически выполнять сборку и публикацию обновлений приложения. Здесь нам поможет Github Actions.Однако в этом месте мы начинаем соприкасаться с организацией процесса, как новые изменения становятся частью существующего кода. Тема довольно обширная, об этом написано много постов, выработаны целые подходы со своими правилами. Поэтому те кто в теме уже и так все знают, а кто не в теме пусть отправляется на поиски чтива Git Flow, Github Flow, Gitlab Flow и их сравнение друг с другом.В нашем случае все просто. Все изменения будут вливаться в master ветку. От ветки master мы создадим release ветку которая и будет источником релизов. Когда мы захотим сделать релиз, просто создадим новый тег и подтянем все изменения из master в release.Теперь когда у нас есть понимание того как вносить изменения и делать релизы можно перейти к настройке workflow в Github Actions. Кто знает нормальный однословный русский перевод слову wokflow дайте знать в комментариях.Будет два workflow:
- Default (.github/workflows/default.yml) - это flow по-умолчанию, выполняет тесты при поступлении новых изменений.
- Release (.github/workflows/release.yml) - это релизный flow делает тесты, сборку Docker образов и пакетов для пакетных менеджеров.
Этот workflow запускается при наступлении push и pull request событий в ветке master. Здесь всего одна задача (job), запуск линтеров и тестов. Github Actions имеет хорошие возможности для кастомизации и позволяют описывать очень сложные сценарии. В нашем случае таким примером кастомизации является запуск и выполнение в специально подготовленном контейнере где есть все необходимое для осуществления тестов.Второй workflow.
---
name: Release
on:
push:
branches: [ release ]
jobs:
test:
runs-on: ubuntu-latest
container: lesovsky/pgcenter-testing:v0.0.1
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Prepare test environment
run: prepare-test-environment.sh
- name: Run lint
run: make lint
- name: Run test
run: make test
build:
runs-on: ubuntu-latest
needs: test
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Build image
run: make docker-build
- name: Log in to Docker Hub
run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
- name: Push image to Docker Hub
run: make docker-push
goreleaser:
runs-on: ubuntu-latest
needs: [ test, build ]
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-go@v2
with:
go-version: 1.15
- uses: goreleaser/goreleaser-action@v2
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Релизный workflow чуть больше, и запускается он при push событиях в release ветке. Этот workflow также включает в себя выполнение линтеров и тестов. Но также тут есть еще две задачи - build и goreleaser. В задаче build выполняется сборка и публикация Docker образа. Обратите внимание, что используются секреты, которые предварительно нужно указать в разделе Secrets, в настройках Github репозитория. В задаче goreleaser выполняется публикация релиза в разделе Releases репозитория. Настройки goreleaser определим позже. Здесь также используется секрет GITHUB_TOKEN его указывать нигде не нужно, он создается автоматически для нужд workflow.GoreleaserПоследний шаг это публикация релиза и дополнительная сборка пакетов. Кроме Docker образов существуют способы распространения с помощью пакетных менеджеров. Наиболее распространенные это deb и rpm пакеты. Есть и другие варианты, но для меня они экзотичны
и их я рассматривать не буду. Для всего этого нам потребуется goreleaser который и сделает всю работу по сборке. Настройки определяются в .goreleaser.yml
before:
hooks:
- make dep
builds:
- binary: pgcenter
main: ./cmd
goarch:
- amd64
goos:
- linux
env:
- CGO_ENABLED=0
ldflags:
- -a -installsuffix cgo
- -X main.gitTag={{.Tag}} -X main.gitCommit={{.Commit}} -X main.gitBranch={{.Branch}}
archives:
- builds: [pgcenter]
changelog:
sort: asc
nfpms:
- vendor: pgcenter
homepage: https://github.com/lesovsky/pgcenter
maintainer: Alexey Lesovsky
description: Command-line admin tool for observing and troubleshooting Postgres.
license: BSD-3
formats: [ deb, rpm ]
Важным моментом является то что goreleaser не имеет интеграции с Makefile и сборку нужно описывать отдельно в формате goreleaser правил. Поэтому важно описать сборку точно так же как это осуществляется в Makefile, т.е. указать все те же флаги, переменные окружения и т.п. В секции nfpms описываем метаданные пакета и указываем необходимые форматы пакетов. Собственно на этом все. Можно фиксировать изменения, пушить в репозиторий, перейти в Actions и наблюдать за тем как выполняются workflow. При успешном выполнении, можем создать новый тег, и влить изменения в релизную ветвь и также понаблюдать за прогрессом в Actions.Спасибо за внимание, если у кого есть дополнения, замечания, вопросы, пожелания - Go в комменты.Ссылки
- Список в gist.github.com
- golangci-lint
- gosec
- Docker multi-stage build
- GitHub Actions Quick Start
- Goreleaser: один и два
===========
Источник:
habr.com
===========
Похожие новости:
- [Производство и разработка электроники, Процессоры, IT-компании] СМИ: Microsoft, Google и Qualcomm недовольны тем, что Nvidia покупает Arm
- [Информационная безопасность, Разработка под iOS, Монетизация мобильных приложений, Контекстная реклама] Google начала обновлять iOS-приложения в соответствии с требованиями Apple
- [Копирайт] Как повысить рейтинг в Google и каких ошибок избегать (перевод)
- [Open source] Google захывтывает Python
- [Google Cloud Platform] Обработка оценок за тесты в Google Forms
- [Программирование, Разработка под Linux, Софт, IT-компании] Цветочные новости: разработчики ОС Fuchsia добавят поддержку запуска немодифицированных Linux-программ
- [Open source, Программирование, Системное программирование, Компиляторы, Rust] Rust 1.50.0: улучшение индексации массивов, безопасность полей объединений и усовершенствование файловых дескрипторов (перевод)
- [PHP, Python, Go] Как PHP/Python разработчиков в Lamoda учат писать на Go
- [SQL, Веб-аналитика, Google Cloud Platform] Работа с dbt на базе Google BigQuery
- [PHP, Разработка под Android, Google API] SafetyNet Attestation — описание и реализация проверки на PHP
Теги для поиска: #_go, #_github, #_go, #_github, #_github_actions, #_makefile, #_goreleaser, #_golangcilint, #_gosec, #_go, #_github
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 08:14
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Пост представляет собой контрольный список (checklist) и его реализацию при публикации Go приложения на Github'е.TLDR:
PROGRAM_NAME = pgcenter
COMMIT=$(shell git rev-parse --short HEAD) BRANCH=$(shell git rev-parse --abbrev-ref HEAD) TAG=$(shell git describe --tags |cut -d- -f1) LDFLAGS = -ldflags "-X main.gitTag=${TAG} -X main.gitCommit=${COMMIT} -X main.gitBranch=${BRANCH}" .PHONY: help clean dep build install uninstall .DEFAULT_GOAL := help help: ## Display this help screen. @echo "Makefile available targets:" @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " * \033[36m%-15s\033[0m %s\n", $$1, $$2}' dep: ## Download the dependencies. go mod download build: dep ## Build pgcenter executable. mkdir -p ./bin CGO_ENABLED=0 GOOS=linux GOARCH=${GOARCH} go build ${LDFLAGS} -o bin/${PROGRAM_NAME} ./cmd clean: ## Clean build directory. rm -f ./bin/${PROGRAM_NAME} rmdir ./bin
lint: dep ## Lint the source files
golangci-lint run --timeout 5m -E golint gosec -quiet ./... test: dep ## Run tests
go test -race -p 1 -timeout 300s -coverprofile=.test_coverage.txt ./... && \ go tool cover -func=.test_coverage.txt | tail -n1 | awk '{print "Total test coverage: " $$3}' @rm .test_coverage.txt # stage 1: build
FROM golang:1.15 as build LABEL stage=intermediate WORKDIR /app COPY . . RUN make build # stage 2: scratch FROM scratch as scratch COPY --from=build /app/bin/pgcenter /bin/pgcenter CMD ["pgcenter"] docker-build: ## Build docker image
docker build -t lesovsky/pgcenter:${TAG} . docker image prune --force --filter label=stage=intermediate docker-push: ## Push docker image to registry docker push lesovsky/pgcenter:${TAG}
---
name: Release on: push: branches: [ release ] jobs: test: runs-on: ubuntu-latest container: lesovsky/pgcenter-testing:v0.0.1 steps: - name: Checkout code uses: actions/checkout@v2 - name: Prepare test environment run: prepare-test-environment.sh - name: Run lint run: make lint - name: Run test run: make test build: runs-on: ubuntu-latest needs: test steps: - name: Checkout code uses: actions/checkout@v2 with: fetch-depth: 0 - name: Build image run: make docker-build - name: Log in to Docker Hub run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - name: Push image to Docker Hub run: make docker-push goreleaser: runs-on: ubuntu-latest needs: [ test, build ] steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - uses: actions/setup-go@v2 with: go-version: 1.15 - uses: goreleaser/goreleaser-action@v2 with: version: latest args: release --rm-dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} и их я рассматривать не буду. Для всего этого нам потребуется goreleaser который и сделает всю работу по сборке. Настройки определяются в .goreleaser.yml before:
hooks: - make dep builds: - binary: pgcenter main: ./cmd goarch: - amd64 goos: - linux env: - CGO_ENABLED=0 ldflags: - -a -installsuffix cgo - -X main.gitTag={{.Tag}} -X main.gitCommit={{.Commit}} -X main.gitBranch={{.Branch}} archives: - builds: [pgcenter] changelog: sort: asc nfpms: - vendor: pgcenter homepage: https://github.com/lesovsky/pgcenter maintainer: Alexey Lesovsky description: Command-line admin tool for observing and troubleshooting Postgres. license: BSD-3 formats: [ deb, rpm ]
=========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 08:14
Часовой пояс: UTC + 5