Первым шагом к выпуску программного обеспечения является этап сборки. Это практическое руководство покажет вам общие принципы автоматизации сборки и эталонные реализации с использованием Семафора. Оптимизация этапа сборки ускорит рабочий процесс разработки и сократит расходы.

Что происходит на этапе сборки

В непрерывной интеграции (CI) мы впервые создаем приложение. Этап сборки — это первый отрезок конвейера CI/CD, на котором автоматизируются такие шаги, как загрузка зависимостей, установка инструментов и компиляция.

Помимо сборки, на этапе сборки мы используем инструменты для проверки безопасности кода и соответствия лучшим практикам. Этап сборки обычно заканчивается этапом генерации артефакта, на котором мы создаем готовый к производству пакет. Как только это будет сделано, можно приступать к этапу тестирования.

Мы подробно расскажем о тестировании в следующих статьях (подпишитесь на рассылку, чтобы не пропустить их). Сегодня мы сосредоточимся на этапе сборки.

На этапе сборки проверяется, может ли приложение при данной фиксации кода пройти дальнейшее тестирование. Мы можем разделить его на три части:

  1. Компиляция: на первом этапе создается приложение.
  2. Linting: проверяет код на программные и стилистические ошибки.
  3. Анализ кода: с помощью инструментов автоматической проверки исходного кода мы контролируем качество кода.
  4. Создание артефакта: последний шаг упаковывает приложение для выпуска или развертывания.

Шаг 1: Компиляция

На первом этапе сборки приложение компилируется. На скомпилированных языках это означает, что мы можем сгенерировать работающий двоичный файл, тогда как на интерпретируемых языках мы подтверждаем, что у нас есть необходимые зависимости и инструменты для успешной сборки приложения.

Результатом может быть бинарный файл, архив кода, устанавливаемый пакет, веб-сайт, образ контейнера — главное, что у нас есть что-то, что мы можем запустить и протестировать.

Шаг 2: Анализ вашего кода

Программирование требует дисциплины. Мы должны решать сложные проблемы, следуя передовой практике и соблюдая общий стиль кодирования. Инструменты автоматизированного анализа помогут вам избавиться от неуклюжего кода. В общих чертах существует три класса инструментов анализа кода:

  • Линтинг: линтеры улучшают качество кода, указывая проблемные и трудно поддерживаемые биты. Линтеры используют набор правил для обеспечения соблюдения единого стандарта, который улучшает читаемость для команды.
  • Качество: этот класс инструментов использует метрики для поиска мест, где можно улучшить код. Собранные метрики включают количество строк, охват документации и уровень сложности.
  • Безопасность: инструменты анализа безопасности сканируют код, помечают части, которые могут вызвать уязвимости, и проверяют, что зависимости не имеют известных проблем с безопасностью.

Поскольку никто не хочет поставлять небезопасный код или код с ошибками, мы должны разработать конвейер непрерывной интеграции, который останавливается при обнаружении ошибок. Когда в конвейере непрерывной интеграции используются правильные инструменты анализа кода, разработчики, проверяющие код, могут сосредоточиться на более важных вопросах, таких как «Решает ли этот код правильную проблему?» или «Увеличивает ли этот код наш технический долг?“.

Шаг 3: Подготовка приложения к выпуску

Выпущенный пакет будет включать в себя все необходимое для запуска или установки приложения, в том числе:

  • Код приложения.
  • Скрипты установки.
  • Зависимости и библиотеки.
  • Метаданные приложения.
  • Документация.
  • Информация о лицензии.

Окончательный пакет может быть опубликован на веб-сайте, в базе данных пакетов, такой как npmjs.com, в реестре контейнеров или может быть непосредственно развернут в QA или рабочей среде.

Полезные команды семафора на этапе сборки

Конвейер CI/CD состоит из блоков и заданий. В семафоре задания — это место, где выполняются ваши команды и код, поэтому именно здесь мы определяем команды для каждого шага на этапе сборки. При настройке этапа сборки вам пригодятся следующие команды Semaphore:

  • оформить заказ: клоны и компакт-диски в репозиторий Git. Обычно это относится к верхней части работы.
  • sem-версия: активирует определенную версию языка. Запустите его, чтобы убедиться, что среда CI использует ту же версию, с которой вы кодируете.
  • кеш: хранит загруженные вами библиотеки, промежуточные и скомпилированные файлы. Кэш — это недолговечное пространство, используемое для передачи файлов между заданиями и рабочими процессами.
  • артефакт: команда artifact позволяет хранить файлы на более постоянной основе. Вы можете получить к ним доступ прямо с веб-сайта. Semaphore предоставляет три уровня для артефактов:
  • job: используется для хранения журналов и других сведений об отладке.
  • рабочий процесс: используется для сохранения файлов между заданиями.
  • проект: используется для хранения окончательных результатов проекта.

Как реализовать стадию сборки с Semaphore

Увидим ли мы несколько практических примеров автоматизации сборки в конвейере непрерывной интеграции? Засучим рукава и напишем код.

Но сначала заметка о том, как я пишу команды:

  • Команды, начинающиеся с $, предназначены для запуска на вашей локальной машине разработки.
  • Команды без знака доллара предназначены для копирования в задания CI.

👉 Перейдите к примеру, который вас больше всего интересует:

  1. Этап сборки Java-приложений
  2. Этап сборки JavaScript-приложений
  3. Этап сборки Python-приложений
  4. Создание образов Docker на этапе сборки

Пример 1: Этап сборки Java-приложений

Java — компилируемый язык, поэтому на этапе сборки исходный код должен быть скомпилирован в байт-код JVM. Вот начальный пайплайн:

Блок компиляции

Ведущими популярными инструментами сборки на Java являются Apache Maven и Gradle, оба входят в машины Semaphore. Пойдем с Maven; он обрабатывает зависимости и компилирует исходный код с помощью одной команды: mvn compile. Используйте эти команды в своем задании CI для создания приложения:

sem-version java 11
checkout
cache restore
mvn compile
cache store

Команда cache обнаружит скомпилированный вывод в каталоге target и сохранит его для будущего использования. В идеале вы должны установить переменную среды MAVEN_OPTS в -Dmaven.repo.local=.m2, чтобы загруженные зависимости также кэшировались.

Линтинг со стилем

Java-разработчики используют мощные IDE, которые анализируют код в реальном времени. Какими бы мощными они ни были, их недостаточно. Проверки качества также должны быть частью конвейера непрерывной интеграции. Мы можем использовать checkstyle, чтобы добавить задание на проверку.

Эти команды загружают checkstyle и запускают его в файле с именем MyFile.java:

sem-version java 11
wget https://github.com/checkstyle/checkstyle/releases/download/checkstyle-8.41/checkstyle-8.41-all.jar
java -jar checkstyle-8.41-all.jar -c /sun_checks.xml MyFile.java

Или, если вы используете Maven, есть плагин для автоматического линтинга. Чтобы включить его, добавьте maven.checkstyle.plugin в свойства вашего файла pom.xml.

<properties>
    <maven.checkstyle.plugin.version>3.1.2</maven.checkstyle.plugin.version>
</properties>

Затем настройте плагин на сбой при ошибке. Добавьте следующий фрагмент в раздел сборки в вашем pom.xml:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-checkstyle-plugin</artifactId>
            <version>${maven.checkstyle.plugin.version}</version>
            <configuration>
                <failsOnError>true</failsOnError>
                <failOnViolation>true</failOnViolation>
            </configuration>
        </plugin>
    </plugins>
</build>

Теперь вы можете запустить checkstyle с помощью:

sem-version java 11
checkout
mvn checkstyle:checkstyle

Поиск ошибок с помощью PMD

Еще одна хорошая программа проверки для использования в среде CI — PMD. PMD работает с Java, JavaScript и Oracle SQL. Вы можете сканировать код с правилами по умолчанию для Java следующим образом:

sem-version java 11
checkout
wget https://github.com/pmd/pmd/releases/download/pmd_releases%2F6.32.0/pmd-bin-6.32.0.zip
unzip pmd-bin-6.32.0.zip
./pmd-bin-6.32.0/bin/run.sh pmd -d . -R rulesets/java/quickstart.xml -f text

Анализ безопасности с Infer

Infer был создан Facebook для поиска кода, который может привести к ошибкам во время выполнения, таким как условия гонки и утечки ресурсов. Infer работает с Java и Android. Facebook открыл этот инструмент и использует его для исправления своего мобильного клиента и основного приложения Facebook.

Чтобы запустить Infer на своем CI, загрузите двоичный файл и соберите приложение. Infer выведет отчет о папке infer-out, который вы можете сохранить для последующего анализа. Следующая команда остановит конвейер при обнаружении проблем:

checkout
cache restore
mvn clean
curl -sSL "https://github.com/facebook/infer/releases/download/v1.0.0/infer-linux64-v1.0.0.tar.xz" | tar -xJ
./infer-linux64-v1.0.0/bin/infer run -- mvn package
artifact push job --expire-in 1w infer-out
./infer-linux64-v1.0.0/bin/infer analyze --fail-on-issue

Поиск ошибок с помощью Find Security Bugs

Найти ошибки безопасности использует базу данных безопасности для обнаружения почти 140 различных типов уязвимостей в веб-приложениях Java.

Чтобы использовать этот инструмент, добавьте этот фрагмент в раздел плагинов в вашем pom.xml:

<plugin>
     <groupId>com.github.spotbugs</groupId>
     <artifactId>spotbugs-maven-plugin</artifactId>
     <version>4.0.4</version>
     <configuration>
         <effort>Max</effort>
         <threshold>Low</threshold>
         <failOnError>true</failOnError>
         <includeFilterFile>${session.executionRootDirectory}/spotbugs-security-include.xml</includeFilterFile>
         <excludeFilterFile>${session.executionRootDirectory}/spotbugs-security-exclude.xml</excludeFilterFile>
         <plugins>
             <plugin>
                 <groupId>com.h3xstream.findsecbugs</groupId>
                 <artifactId>findsecbugs-plugin</artifactId>
                 <version>1.10.1</version>
             </plugin>
         </plugins>
     </configuration>
</plugin>

Затем создайте два файла: spotbugs-include.xml и spotbugs-exclude.xml. Содержимое первого:

<FindBugsFilter>
     <Match>
         <Bug category="SECURITY"/>
     </Match>
</FindBugsFilter>

Вы можете исключить правила в файле исключений:

<FindBugsFilter></FindBugsFilter>

Зафиксируйте изменения в своем репозитории. Затем создайте задание, которое создает отчет и отправляет его в хранилище артефактов:

checkout
cache restore 
mvn spotbugs:spotbugs 
artifact push job target/spotbugsXml.xml  --expire-in 1w 
mvn spotbugs:check

Создание JAR-файла

Мы можем сгенерировать файл JAR с: mvn package. Поскольку мы уже протестировали приложение, мы можем пропустить тесты.

sem-version java 11
checkout 
cache restore 
mvn package 
cache store

Выходной JAR загружается в хранилище артефактов, откуда его можно загрузить или использовать в конвейерах непрерывной доставки и развертывания.

👉 Полный пример настройки конвейера CI/CD для приложений Java см. в разделе CI/CD для микросервисов Spring Boot.

Пример 2: Этап сборки для приложений JavaScript

Код JavaScript не требует компиляции. На этапе сборки будут загружаться только зависимости, затем выполняется анализ кода и, наконец, сборка пакета.

Заполнение node_modules

Мы можем установить модули JavaScript с помощью npm:

checkout 
npm ci

Команда npm ci создает чистую копию папки node_modules. К сожалению, в результате мы не можем использовать кеш на данном этапе. npm ci — это самый чистый и безопасный способ установки модулей.

Но если вы хотите или должны использовать кеш, вам нужно запустить npm install вместо npm ci:

sem-version node 14.16 
checkout 
cache restore 
npm install 
cache store

Если проект включает файл конфигурации .nvmrc, вы можете заменить sem-version на nvm use:

checkout 
nvm use 
cache restore 
npm install 
cache store

В состав машины КИ также входит пряжа:

sem-version node 14.16 
checkout 
cache restore 
yarn install 
cache store

Линтинг с помощью ESLint и JSHint

JavaScript прошел долгий путь со времен Netscape. Он вырос из языка, созданного менее чем за десять дней, в самое близкое к лингва-франка, что у нас есть — почти все устройства поддерживают JavaScript.

Как вы понимаете, язык со временем сильно изменился, и не все его части хороши. Использование линтера поможет нам избежать плохих частей JavaScript. По моему опыту, линтеры ESlint и JSHint очень хорошо интегрируются в среду CI. Любой из них можно установить с помощью npm install --save-dev.

Для ESLint вам нужно создать конфигурацию с:

$ npx eslintrc --init

Затем добавьте его в раздел сценария package.json:

"scripts": {
     "lint": "eslint '**/*.js' --ignore-pattern node_modules",
     ...
 }

После фиксации изменений используйте следующее для запуска линтера:

sem-version node 14.16 
checkout 
npm run lint

Аудит безопасности: npm и AuditJS

Аудит безопасности встроен в npm. Вы можете проверить свои зависимости с помощью npm audit. Обратите внимание, однако, что вы должны установить пороговый уровень, чтобы команда завершилась ошибкой:

sem-version node 14.16 
checkout 
cache restore 
npm audit --audit-level=high

Если вы обнаружите проблемы с безопасностью, попробуйте запустить npm audit fix для автоматического решения.

Альтернативой npm audit является AuditJS. Этот инструмент использует индекс уязвимостей OSS, который поступает из многих баз данных безопасности, поэтому результаты являются более точными.

Вы можете добавить AuditJS в свой проект с помощью:

$ npm install --save-dev auditjs

Затем используйте следующую команду для запуска теста:

sem-version node 14.16
checkout
npx auditjs ossi

Одна приятная особенность AuditJS заключается в том, что она позволяет нам заносить в белый список проблемы безопасности. Это здорово, например, когда мы хотим игнорировать уязвимость, потому что знаем, что она не влияет на нас.

Для этого создайте файл JSON с подробным описанием идентификатора уязвимости и причины ее игнорирования:

{
  "ignore": [
    {
        "id": "78a61524-80c5-4371-b6d1-6b32af349043",
        "reason": "Vulnerability doesn't affect our code"
    }
  ]
}

Затем запустите AuditJS с включенным белым списком:

sem-version node 14.16
checkout
auditjs ossi --whitelist my-whitelist.json

Создание пакетов узлов

Используйте npm pack, чтобы создать архив, который вы можете распространять, или используйте npm publish, чтобы загрузить модуль на npmjs.com.

checkout
tarfile=$(npm pack)
artifact push project --force "$tarfile"

👉 Полный пример настройки конвейера CI/CD для приложения JavaScript см. в разделе Как создать и развернуть приложение Node.js в Kubernetes или Непрерывная интеграция с Deno.

Пример 3: Этап сборки для приложений Python

Нам не нужно запускать какие-либо команды компиляции в Python. В результате задание сборки, как и задание JavaScript, будет загружать и кэшировать только зависимости.

Установка модулей

В этом примере мы запускаем pip, чтобы установить зависимости проекта в папку .pip_cache:

sem-version python 3.9
checkout
cache restore
pip download --cache-dir .pip-cache -r requirements.txt
cache store

Линтинг с Pylint

Разработчики Python привыкли следовать строгим стандартам кодирования. Один из хороших способов проверки стиля — Pylint. Набор правил Pylint включает проверки неиспользуемых модулей, форматов имен переменных и длины строки. Он строго соответствует руководству по стилю Python PEP 8.

Как и большинство линтеров, Pylint можно интегрировать в IDE. Но в этом случае мы будем использовать его в пайплайне для проверки качества фиксации. Чтобы показать ошибки lint в одном пакете или файле, используйте:

sem-version python 3.9
checkout
pylint -E [MODULE|PYTHON_FILE]

Вы можете сканировать каждый файл Python в репозитории с помощью следующей команды:

sem-version python 3.9
checkout
git ls-files | grep -E '.py$' | xargs pylint -E

Анализ сложности с Xenon

Одна вещь, которую руководство по стилю PEP 8 не может учесть, — это цикломатическая сложность, мера того, сколько независимых путей существует в кодовой базе. Для его расчета можно использовать такой инструмент, как Ксенон.

Чтобы начать работу с Xenon, добавьте его в свой проект Python с помощью:

$ pip install xenon
$ pip freeze > requirements.txt

Xenon использует систему ранжирования, которая идет от A до F, где A — самый низкий уровень сложности. В задании вы можете указать минимальный допустимый уровень, прежде чем потерпеть неудачу.

sem-version python 3.9
checkout
cache restore
xenon --max-absolute C --max-modules B --max-average A

Пример приведет к сбою задания, если средняя сложность ниже A, сложность модулей ниже B или сложность блока ниже C.

Упаковка для раздачи

Пакет формат Python позволяет загружать модули в официальный индекс PyPI или распространять его на своем веб-сайте.

Чтобы создать пакет, используйте следующие команды:

sem-version python 3.9
python -m pip install --upgrade build
checkout
python -m build
artifact push project --force dist

👉 Полный конвейер Python см. в разделе Непрерывная интеграция и развертывание Python с нуля.

Пример 4: Создание образов Docker на этапе сборки

Docker — контейнерная платформа, позволяющая упаковывать любое программное обеспечение независимо от языка. Создавая образ Docker, мы получаем переносимое приложение, которое можно запускать на любом компьютере (при условии, что на нем установлена ​​среда выполнения контейнера). Это также позволяет нам запускать приложение в масштабе на платформах оркестрации, таких как Docker Swarm или Kubernetes.

Semaphore включает в себя все необходимое для создания образа Docker. Вам нужно только предоставить Dockerfile с инструкциями по сборке.

Самый простой способ написать Dockerfile — начать с базового образа. Semaphore предоставляет изображения для популярных языков в Semaphore Container Registry. Например, этот Dockerfile предназначен для упаковки приложения Python:

# use image in Semaphore container registry
FROM registry.semaphoreci.com/python:3.9
# copy source files
ADD . ./opt/
WORKDIR /opt/
# install dependencies
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
# start application
CMD ["python","app.py"]

Используйте эти команды в задании CI для создания образа:

checkout
docker build -t my-image .

Это работает, но изображение теряется, как только задание завершается. Мы должны загрузить его в реестр, чтобы сохранить его. И для этого вы должны предоставить информацию для входа в реестр изображений с секретом.

Чтобы создать секрет, нажмите значок своей учетной записи в правом верхнем углу и выберите Настройки.

Затем нажмите СекретыНовый секрет.

Создайте секрет под названием dockerhub с вашим именем пользователя и паролем Docker Hub:

Теперь вы можете получить доступ к имени пользователя и паролю в задании:

echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin

Затем вы можете вытащить последний образ, чтобы ускорить процесс сборки:

docker pull $DOCKER_USERNAME/awesome-application:latest || true

Наконец, создайте и отправьте образ:

docker build -t $DOCKER_USERNAME/awesome-application:latest --cache-from=$DOCKER_USERNAME/awesome-application:latest .
docker push $DOCKER_USERNAME/awesome-application:latest

Полные рабочие команды:

echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker pull $DOCKER_USERNAME/awesome-application:latest || true
docker build -t $DOCKER_USERNAME/awesome-application:latest --cache-from=$DOCKER_USERNAME/awesome-application:latest .
docker push $DOCKER_USERNAME/awesome-application:latest

Не забудьте активировать секрет в своей работе:

То, что мы видели, — это основные строительные блоки для образа Docker. Процесс в основном одинаков для любого языка. Единственное, что меняется, — это содержимое Dockerfile. У нас есть несколько подробных руководств и примеров файлов Dockerfile, которые вы можете просмотреть ниже:

Что дальше

Мы узнали, что такое этап сборки, и увидели немало примеров конвейеров сборки. Принципы всегда остаются одними и теми же, независимо от используемого языка или фреймворка.

Принцип, используемый во всех примерах, заключается в том, что стадия сборки выполняется в конвейере. Запуская быстрые проверки кода сразу после компиляции — и перед набором автоматизированных тестов — вы оптимизируете процесс непрерывной интеграции для быстрой обратной связи.

Я надеюсь, что эти рекомендации помогут вам оптимизировать процесс сборки. Удачного строительства!

Первоначально опубликовано на https://semaphoreci.com 24 марта 2021 г.