Русский
Русский
English
Статистика
Реклама

Ci

Перевод Как криптомайнеры убивают бесплатные CI

28.04.2021 20:06:12 | Автор: admin

СI-платформы, такие как LayerCI, GitLab, TravisCI, и Shippable ухудшают, а то и вовсе закрывают свои бесплатные сервера из-за атак с целью скрытого майнинга.

1 сентября 2020 года GitLab объявил что ограничивает бесплатное использование CI в ответ на эксплуатацию. Два месяца спустя TravisCI анонсировал схожие ограничения из-за серьезных злоупотреблений. В это же время возросла рыночная капитализация добываемых криптовалют.

Рыночная капитализация криптовалюты подскочила со 190 млрд до 2 трлн за один год.Рыночная капитализация криптовалюты подскочила со 190 млрд до 2 трлн за один год.

Эти события связаны между собой: поскольку рыночная капитализация криптовалюты выросла с 190 млн. долларов в январе 2020 до 2 триллионов в апреле 2021, злоумышленникам стало выгодно атаковать бесплатные сервера PaaS провайдеров.

Контекст

В LayerCI мы помогаем разработчикам создавать полнофункциональные веб-сайты, создавая среды предварительного просмотра и автоматически запуская для них E2E тесты. Это называется CI (Непрерывная интеграция).

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

717 GitHub коммитов за один месяц

testronan заядлый пользователь Flask. Каждый час он делает коммит в своем единственном GitHub репозитории: testronan/MyFirstRepository-Flask.

Продуктивный программист, безусловно, должен убедиться в том, что внесенные им изменения хорошо протестируются. Поэтому его репозиторий содержит конфигурации аж для пяти разных CI-платформ: TravisCI, CircleCI, GitHub Actions, Wercker, и LayerCI.

Похоже он довольно опытен в написании скриптов. Его СI таски запускают listhen.sh: shell скрипт, который объединяет сложный NodeJS скрипт с, на первый взгляд, случайными числами:

(sleep 10; echo 4; sleep 2; echo "tex.webd";sleep 2; echo 7; sleep 1; echo 1; sleep 1; echo "exit"; sleep 2) | stdbuf -oL npm run commands  

MyFirstRepository-Flask не имеет ничего общего с Flask или веб-серверами. В нем размещены скрипты для майнинга криптовалюты, которые отправляют WebDollars (прим. криптовалюта) на анонимный адрес. Числа соответствуют настройкам реализации WebDollar на NodeJS.

Репозиторий не атакует GitHub напрямую, вместо этого он злоупотребляет функцией cron для создания нового коммита каждый час и майнинга WebDollar на четырех оставшихся платформах.

При пиковой апрельской цене WebDollar в 0.0005 долларов репозиторий зарабатывал 77 долларов в месяц значительная для многих стран сумма, особенно учитывая, что для заработка необходим лишь ноутбук и интернет-соединение.

Два кошелька, на который приходит добытая криптовалюта:

Майнинг криптовалюты в браузере

Пользователь vippro99 описывает свои намерения менее изящно. Из десятков репозиториев большинство связано либо с криптовалютой либо с автоматизацией браузера.

Репозиторий nodejs-monney содержит различные скрипты для запуска экземпляров Chrome c популярным гугловским puppeteer project.

Идея проста: майнинг криптовалюты непосредственно в CI довольно легко обнаружить (например, с помощью анализа исполняемого содержимого), но автоматизация браузера это обычная рабочая нагрузка в CI.

puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox', '--window-size=500,500', '--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36' ] }).then(async browser => {  console.log('-- Running chrome!!'); const page = await browser.newPage(); await page.goto('https://vippro99.github.io/-meocoder-nodejs-tool/index.html');  page.on('console', (msg) => console.log(msg.text())); await page.waitForTimeout(((Math.floor(Math.random() * 6) + 52) * 60) * 1000); await browser.close(); })

Данный GitHub Pages веб-сайт содержит простой браузерный майнер криптовалюты Monero, напоминающий Coinhive.

На момент написания аккаунт атаковал JFrog's Shippable CI, которая (возможно, в связи с этим) анонсировала об окончании поддержки бесплатных серверов в начале этого года.

Судя по комментариям vippro99, он проживает во Вьетнаме. При текущей цене Monero, каждый экземпляр майнера на Shippable приносит 2.5 доллара в месяц, поэтому поддержание 60 экземпляров равносильно полному рабочему дню в этой стране.

Решение проблемы

Ethereum, вторая по популярности криптовалюта, недавно объявила о планах прекращения поддержки майнинга на основе вычислений, полностью переключившись на модель Proof-of-Stake (PoS).

Помимо негативного воздействия традиционного proof-of-work майнинга на окружающую среду, существуют и другие неприятные аспекты: мировая нехватка графических процессоров и атаки на CI-платформы.

Провайдеры будут делать все возможное, чтобы обеспечить соблюдение условий обслуживания, но пока атаки выгодны и трудноотслеживаемы, они будут приобретать все более изощренный характер. Единственный долгосрочный способ и дальше пользоваться бесплатными серверами в Heroku, Netlify и GitHub это отказ от proof-of-work.


Дата-центр ITSOFT размещение и аренда серверов и стоек в двух дата-центрах в Москве. За последние годы UPTIME 100%. Размещение GPU-ферм и ASIC-майнеров, аренда GPU-серверов, лицензии связи, SSL-сертификаты, администрирование серверов и поддержка сайтов.

Правильно и недорого майнить криптовалюту можно в майнинг-отелеhttps://itsoft.ru/data-center/mining/

Подробнее..

Перевод Dockle Диагностика безопасности контейнеров

07.06.2021 20:11:26 | Автор: admin

В этой статье мы рассмотрим Dockle инструмент для проверки безопасности образов контейнеров, который можно использовать для поиска уязвимостей. Кроме того, с его помощью можно выполнять проверку на соответствие Best Practice, чтобы убедиться, что образ действительно создаётся на основе сохраненной истории команд.

Установка Dockle

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

  • Установка в OSX

$ brew install goodwithtech/r/dockle
  • Установка в Linux

# RHEL$ VERSION=$( curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \ grep '"tag_name":' | \ sed -E 's/.*"v([^"]+)".*/\1/' \) && rpm -ivh https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.rpm#Ubuntu$ VERSION=$( curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \ grep '"tag_name":' | \ sed -E 's/.*"v([^"]+)".*/\1/' \) && curl -L -o dockle.deb https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.deb$ sudo dpkg -i dockle.deb && rm dockle.deb

После установки утилиты всё, что вам нужно сделать, это указать имя образа. Больше ничего настраивать не нужно, вам даже не потребуется Docker.

Пример использования Dockle

Запускаем утилиту, указав имя образа. Если проблем нет, в консоль будет выведено сообщение PASS, а при обнаружении проблем или уязвимостей подробная информация о них:

Попробуем запустить Dockle в Docker, на скриншоте видно, что утилита отлично работает:

Основные функции и преимущества Dockle

  • поиск уязвимостей в образах,

  • помощь в создании правильного Dockerfile,

  • простота в использовании, нужно указать только имя изображения,

  • поддержка CIS Benchmarks.

Сравнение с другими инструментами

Существует большое количество похожих инструментов для диагностики безопасности, например: Docker Bench или Hadolint. Но в сравнении с ними Dockle более функциональна:

Применение Dockle в DevSecOps

Думаю, что эта небольшая статья хорошая отправная точка для начала работы с Dockle. Она может легко использоваться в CI, улучшит ваши пайплайны в соответствии с концепцией DevSecOps.

По ссылкам ниже вы можете найти примеры того, как настроить системы CI / CD для работы с Dockle:

Подробнее..

Пишем простейший GitHub Action на TypeScript

09.06.2021 16:12:52 | Автор: admin

Недавно я решил немного привести в порядок несколько своих .NET pet-проектов на GitHub, настроить для них нормальный CI/CD через GitHub Actions и вынести всё в отдельный репозиторий, чтобы все скрипты лежали в одном месте. Для этого пришлось немного поизучать документацию, примеры и существующие GitHub Actions, выложенные в Marketplace.

В данной статье я решил собрать самую основную информацию, которая нужна для того, чтобы написать простейший GitHub Action с использованием TypeScript.

Статья в первую очередь рассчитана на начинающих, тех, кто никогда не использовал GitHub Actions, но хотел бы быстро начать. Тем не менее, даже если у вас уже есть подобный опыт, но вы, например, не использовали ncc, то, возможно, и для вас в ней будет что-то полезное.

Краткое введение в GitHub Actions

В основе GitHub Actions лежит понятие Workflow - некий рабочий процесс, который запускается по определённым триггерам. В одном репозитории может быть как один рабочий процесс, так и несколько отдельных, срабатывающий при разных условиях.

Чтобы добавить рабочий процесс, нужно создать в репозитории один или несколько yml-файлов в папке .github/workflows. Простейший файл может выглядеть следующим образом:

name: Helloon: [push]jobs:  Hello:    runs-on: ubuntu-latest    steps:      - name: Checkout        uses: actions/checkout@v2      - name: Hello        run: echo "Hello, GitHub Actions!"

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

Сам рабочий процесс мы можем найти на вкладке Actions в интерфейсе GitHub и посмотреть детальную информацию по нему:

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

Каждый джоб состоит из набора шагов, которые последовательно запускаются внутри одной виртуальной машины. Каждый такой шаг в свою очередь может либо выполнять произвольную команду через run, либо может запускать какое-то действие через uses.

Сами действия представляют из себя отдельный кусок рабочего процесса, который можно повторно использовать в нескольких проектах. Они могут быть трёх видов: докер контейнер, действие JavaScript, или составные действия (которые по сути просто переиспользуемый набор других действий). Вариант с действием JavaScript мы как раз и рассмотрим в этой статье, но писать его будем на TypeScript для большего удобства.

(Более подробную информацию по возможностям рабочих процессов можно найти в документации)

Пара слов о месте размещения действий в репозитории

Действия можно разместить в репозитории в нескольких местах в зависимости от потребностей:

  • В подпапке .github/actions. Такой способ обычно используется когда вы хотите использовать эти действия из того же репозитория. В этом случае ссылаться на них необходимо по пути без указания ветки или тега:

    steps:  - uses: ./.github/actions/{path}
    
  • В произвольном месте репозитория. Например, можно разместить несколько действий в корне репозитория, каждое в своей подпапке. Такой способ хорошо подходит, если вы хотите сделать что-то вроде личной библиотеки с набором действий, которые собираетесь использовать из разных проектов. В этом случае ссылаться на такие действия нужно по названию репозитория, пути и ветке или тегу:

    steps:  - uses: {owner}/{repo}/{path}@{ref}
    
  • В корне репозитория. Такой способ позволяет разместить в одном репозитории только одно действие, и обычно используется если вы хотите позже опубликовать его в Marketplace. В этом случае ссылаться на такие действия нужно по названию репозитория и ветке или тегу:

    steps:  - uses: {owner}/{repo}@{ref}
    

Создаём действие на TypeScript

В качестве примера создадим очень простое действие, которое просто выводит сообщение Hello, GitHub Actions!. Для разработки действия нам потребуется установленная версия Node.js (я использовал v14.15.5).

Создадим в репозитории папку .github/actions. В ней создадим подпапку hello, в которой будем далее создавать все файлы, относящиеся к нашему действию. Нам потребуется создать всего четыре файла.

Создаём файл action.yml:

name: Hellodescription: Greet someoneruns:  using: node12  main: dist/index.jsinputs:  Name:    description: Who to greet    required: true

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

Также мы указываем, что это именно JavaScript действие, а не докер контейнер и указываем точку входа: файл dist/index.js. Этого файла у нас пока нет, но он будет автоматически создан чуть позже.

Кроме этого мы можем указать в этом файле набор входных и выходных параметров. В данном случае мы передаём в качестве параметра имя для приветствия.

(Более подробную информацию по возможностям файла метаданных можно найти в документации)

Создаём файл package.json:

{  "private": true,  "scripts": {    "build": "npx ncc build ./src/main.ts"  },  "dependencies": {    "@actions/core": "^1.2.7",    "@actions/exec": "^1.0.4",    "@actions/github": "^4.0.0",    "@actions/glob": "^0.1.2",    "@types/node": "^14.14.41",    "@vercel/ncc": "^0.28.3",    "typescript": "^4.2.4"  }}

Это стандартный файл для Node.js. Чтобы не указывать бесполезные атрибуты типа автора, лицензии и т.п. можно просто указать, что пакет private. (При желании можно конечно всё это указать, кто я такой, чтобы вам это запрещать =)

В скриптах мы указываем один единственный скрипт сборки, который запускает утилиту ncc. Эта утилита на вход получает файл src/main.ts и создаёт файл dist/index.js, который является точкой входа для нашего действия. Я вернусь к этой утилите чуть позже.

В качестве зависимостей мы указываем typescript и @types/node для работы TypeScript. Зависимость @vercel/ncc нужна для работы ncc.

Зависимости @actions/* опциональны и являются частью GitHub Actions Toolkit - набора пакетов для разработки действий (я перечислил самые на мой взгляд полезные, но далеко не все):

  • Зависимость @actions/core понадобится вам вероятнее всего. Там содержится базовый функционал по выводу логов, чтению параметров действия и т.п. (документация)

  • Зависимость @actions/exec нужна для запуска других процессов, например dotnet. (документация)

  • Зависимость @actions/github нужна для взаимодействия с GitHub API. (документация)

  • Зависимость @actions/glob нужна для поиска файлов по маске. (документация)

Стоит также отметить, что формально, поскольку мы будем компилировать наше действие в один единственный файл dist/index.js через ncc, все зависимости у нас будут зависимостями времени разработки, т.е. их правильнее помещать не в dependencies, а в devDependencies. Но по большому счёту никакой разницы нет, т.к. эти зависимости вообще не будут использоваться во время выполнения.

Создаём файл tsconfig.json:

{  "compilerOptions": {    "target": "ES6",    "module": "CommonJS",    "moduleResolution": "Node",    "strict": true  }}

Тут всё достаточно просто. Это минимальный файл, с которым всё хорошо работает, включая нормальную подсветку синтаксиса и IntelliSense в Visual Studio Code.

Создаём файл src/main.ts:

import * as core from '@actions/core'async function main() {  try {    const name = core.getInput('Name');    core.info(`Hello, ${name}`);  } catch (error) {    core.setFailed(error.message)  }}main();

В качестве точки входа мы используем синхронную или асинхронную функцию main, которую вызываем в этом же файле. (Название функции также может быть любым).

Тело функции необходимо обернуть в блок try-catch, чтобы в случае любых ошибок сборка в GitHub прерывалась. Без этого она всегда будет считаться успешной.

В данном конкретном случае мы также используем пакет @actions/core для чтения параметров и вывода сообщения в лог.

Собираем действие при помощи ncc

После того, как все файлы созданы нам первым делом необходимо восстановить все пакеты из npm. Для этого нам нужно перейти в папку действия (не в корень репозитория) и выполнить команду:

npm install

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

В качестве альтернативы можно воспользоваться пакетом @vercel/ncc, который позволяет собрать js или ts-файлы в один единственный js-файл, который уже можно закоммитить в репозиторий.

Поскольку мы уже указали скрипт для сборки в файле package.json, нам осталось только запустить команду:

npm run build

В результате мы получим файл dist/index.js, который нужно будет закоммитить в репозиторий вместе с остальными файлами. Папка node_modules при этом может быть спокойно отправлена в .gitignore.

Используем действие

Чтобы протестировать действие, создадим в папке .github/workflows файл рабочего процесса. Для разнообразия сделаем так, чтобы он запускался не по пушу, а вручную из интерфейса:

name: Helloon:  workflow_dispatch:    inputs:      Name:        description: Who to greet        required: true        default: 'GitHub Actions'jobs:  Hello:    runs-on: ubuntu-latest    steps:      - name: Checkout        uses: actions/checkout@v2      - name: Hello        uses: ./.github/actions/hello        with:          Name: ${{ github.event.inputs.Name }}

Здесь настройки workflow_dispatch описывают форму в интерфейсе GitHub в которую пользователь сможет ввести данные. Там у нас будет одно единственное поле для ввода имени для приветствия.

Данные, введённые в форму через событие передаются в действие, которое мы запускаем в рабочем процессе через параметр github.event.inputs.Name.

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

После того, как мы запушим наш рабочий процесс, мы можем перейти в интерфейс GitHub, на странице Actions выбрать наш рабочий процесс и запустить его выполнение, указав параметры:

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

Настраиваем GitHooks для автоматической сборки

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

Каждый раз, когда мы будем изменять код действия нам нужно не забыть вызвать команду:

npm run build

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

Решить эту проблему можно несколькими способами. Можно не париться и действительно каждый раз запускать сборку руками. В некоторых проектах люди подходят к этому основательно и делают специальный рабочий процесс через тот же GitHub Actions, который на каждый коммит пытается пересобрать действие и коммитит изменения.

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

#!/bin/shfor action in $(find ".github/actions" -name "action.yml"); do    action_path=$(dirname $action)    action_name=$(basename $action_path)    echo "Building \"$action_name\" action..."    pushd "$action_path" >/dev/null    npm run build    git add "dist/index.js"    popd >/dev/null    echodone

Здесь мы находим все файлы action.yml в папке .github/actions и для всех найденных файлов запускаем сборку из их папки. Теперь нам не нужно будет думать о явной пересборке наших действий, она будет делаться автоматически.

Чтобы хуки из папки .githooks запускались, нам необходимо поменять конфигурацию для текущего репозитория:

git config core.hooksPath .githooks

Или можно сделать это глобально (я сделал именно так):

git config --global core.hooksPath .githooks

Заключение

В данной статье я постарался собрать основную информацию, необходимую для того, чтобы быстро сделать первый шаг к GitHub Actions и начать писать свои собственные скрипты автоматизации на TypeScript.

Репозиторий с примером можно найти тут: https://github.com/Chakrygin/hello-github-action

Подробнее..

Организация кодовой базы и тестирования в монорепозиторий

09.10.2020 16:18:18 | Автор: admin

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



Текущее положение дел


Юнит BuyerX отвечает застраницы и функциональность, которая помогает пользователю выбирать товары наАвито. То есть мы стараемся сделать пользователя покупателем. Кнашей зоне ответственности относятся главная страница, страницы объявлений и страницы споисковой выдачей. Страницы споисковой выдачей могут быть специфичными подопределённые категории: например, где-то не нужны поисковые фильтры или нужен особый заголовок страницы и расположение самих элементов.



Главная страница Авито



Страница поисковой выдачи



Страница объявления


Разработка этих страниц вызывала определённые проблемы:


  • Все шаблоны жили вогромной основной кодовой базе, где было сложно ориентироваться и вносить изменения.
  • После внесения даже маленьких изменений сборка проекта занимала продолжительное время до5-10 минут вхудшем случае и потребляла большое количество ресурсов компьютера.
  • Когда хотелось, чтобы отдельные компоненты работали наReact-е, приходилось дублировать вёрстку и вшаблоне, и вкомпоненте длятого, чтобы сделать механизм серверного рендеринга.

Кроме того, главная страница, страницы объявлений и страницы споисковой выдачей позволяют создать непрерывный сценарий покупки дляпользователя. Поэтомув своё время мы приняли решение переписать их слегаси-технологии Twig наReact, чтобы вбудущем перейти наSPA-приложение, а также оптимизировать процесс загрузки компонентов длякаждой изстраниц. Так, кпримеру, сниппет объявления наглавной и странице поиска одинаковый. Тогда зачем грузить его два раза?


В связи сэтим появился npm-пакет, который мы гордо назвали single-page. Задача этого пакета содержать внутри себя верхнеуровневое описание каждой изстраниц. Это описание того, изкаких React-компонентов состоит страница, и вкаком порядке и месте они должны быть расположены. Также пакет призван управлять загрузкой нужных и выгрузкой уже ненужных компонентов, которые представляют собой небольшие React+Redux приложения, вынесенные вотдельные npm-пакеты.


Например, припереходе настраницу срезультатами поиска, пользователю необходимы поисковые фильтры, которые позволят сузить выдачу. Вданном случае single-page определяет, что необходимо запросить пакет сфильтрами и делает соответствующий запрос. Если пользователь уже перешёл настраницу объявления, то поисковые фильтры ему не нужны, а значит и сам пакет можно не использовать, чтобы он не ухудшал производительность страницы.


Сам пакет single-page уже работает как описано. Однако длятого, чтобы все описанные механики приносили пользу, переход между страницами должен быть бесшовным, как вSPA-приложениях. Ксожалению, намомент написания статьи бесшовных переходов между страницами нет. Но это не значит, что их не будет. То, каким образом сейчас работает пакет single-page это основа, которую мы будем развивать дальше. Она уже задала определённые правила, связанные сорганизацией кодовой базы, которых мы вюните придерживаемся.


Расскажу, как именно происходила эволюция работы срепозиториями npm-пакетов, и кчему мы пришли.


Отдельные репозитории для npm-пакетов


Как я упоминал ранее, изначально главная страница и страница споисковой выдачей были написаны сиспользованием шаблонизатора Twig. Был один большой шаблон страницы, который импортировал всебя более мелкие шаблоны отдельных компонентов страницы.


Это немного похоже навёрстку черезReact-компоненты, но проблема была втом, что вовсех шаблонах было много бизнес-логики, которая усложняла процесс чтения и внесения изменений. Плюс, из-за того, что каждая страница это отдельный шаблон, припереходах пользователя между страницами приходилось грузить всю страницу заново, даже если некоторые компоненты переиспользовались междушаблонами. Это увеличивало время ответа приобращении пользователя закакой-либо страницей, что не лучшим образом сказывалось наUX и SEO.


Стало понятно, что необходимо переходить нановый стек React. Переход проходил поэтапно. Сначала вюните договорились, что все новые компоненты будут написаны сразу наReact-е и будут рендериться настраницу послееё загрузки. Эти компоненты слабо влияли наSEO, поэтому подход имел право нажизнь. Пример такого компонента блок спросмотренными и избранными объявлениями наглавной странице:



Для работы новых компонентов наReact-е иногда нужны были уже существующие компоненты, написанные наTwig-е. Поэтому мы начали переносить некоторые изних наReact вурезанном виде. Так, кпримеру, сниппет, который используется вблоке просмотренных объявлений, был частично перенесён нановый стек, хотя наTwig весь шаблон сразличными условиями, влияющими наинформацию всниппете, содержал более 1000строк.



Сниппет вблоке просмотренных объявлений, который был перенесён сразу нановый стек


А вот как выглядят сниппеты вразличных категориях:



Сниппет вкатегории бытовой электронике



Сниппет вкатегории работа



Сниппет вкатегории недвижимость



Сниппет вкатегории автомобили


Вынос вnpm-пакет это только часть работы. Длятого, чтобы пакет был полезен, он должен быть использован восновной кодовой базе. Поскольку все компоненты это отдельные пакеты, то вмонолите (основной кодовой базе) необходимо подключить их как зависимости, а далее проинициализировать эти пакеты вкоде. Так как блок просмотренных объявлений и сниппет были выделены вотдельные npm-пакеты, то вкодовой базе монолита они были подключены как зависимости. Чтобы увидеть изменения, которые появились сновой версией пакета, достаточно поднять его версию безвнесения каких-либо дополнительных изменений.


Как видите, между пакетами уже появляются зависимости: монолит зависит откомпонента блока просмотренных и избранных объявлений, который всвою очередь зависит откомпонентов сниппета. Но вданном случае связь небольшая, поэтому после внесения изменений вnpm-пакет сниппетов необходимо:


  • поднять его версию;
  • опубликовать её;
  • подключить новую версию вкомпоненте правого блока;
  • поднять его версию;
  • поднять версию вмонолите.

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


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


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


Уподхода, когда каждый npm-пакет жил всвоём репозитории, был и свой плюс. Приподнятии версии зависимости вкаком-нибудь пакете, необходимо было убедиться, что этот пакет не сломается приработе насайте. То есть нужно было протестировать все внесённые изменения. Проверки побольшей части приходилось делать руками существовавшего набора тестов и инструментария было недостаточно дляпокрытия большинства сценариев. А принахождении каких-либо багов втестируемом пакете, их нужно было исправить. Поэтому нередко присутствовала практика, когда версию зависимости поднимали не везде, а только там, где это необходимо. Содной стороны, это усугубляло рассинхронизацию версий зависимых пакетов, а с другой сильно упрощало тестирование засчёт отсутствия некоторых проверок.


Однако вкакой-то момент рассинхронизация версий зависимостей привела кновым проблемам: пакет мог содержать сильно старую зависимость и простое её обновление могло сломать работу всего пакета. Из-заэтого приходилось тратить лишнее время наактуализацию зависимостей, внесение правок всам пакет и, возможно, взависимые тоже, а также натестирование этого пакета. Конечно, вкаждом репозитории были тесты, чтобы проверить, что всё работает корректно. Но тесты были только скриншотные, что ограничивало круг покрываемых вещей. Плюс не вовсех репозиториях был подключен CI, чтобы тесты прогонялись накаждом пул-реквесте.


Что получилось наэтом этапе:


  1. Количество связанных пакетов выросло.
  2. Каждый пакет жил вотдельном репозитории.
  3. Вкаждый репозиторий создавался пул-реквест свнесением изменений, связанных споднятием версий зависимости.
  4. Ситуация, когда пакет не имел последнюю актуальную версию зависимости была нормой. Плюс, кэтому моменту уже создавался пакет single-page, который взависимостях имел все ранее созданные пакеты.

Всё это привело к тому, что мы начали искать пути дляулучшения работы срепозиториями и всеми нашими пакетами.


Переход к монорепозиторию


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


После небольшого эксперимента и ресёрча, стало понятно, что Lerna поможет решить часть наших проблем:


  • С ней не будет необходимости вкаждом пакете самим поднимать версии зависимых пакетов.
  • Отпадёт необходимость постоянно помнить прозависимости, потому что Lerna знает, какие пакеты какими версиями связаны.
  • Количество пул-реквестов уменьшится доодного, вкотором видны все зависимости, которые будут изменены.

Мы завели отдельный репозиторий, вкоторый начали переносить все пакеты и связывать их зависимостями черезLerna.


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


Длярешения этой задачи внутри нашего юнита нашелся доброволец, который хорошо разобрался вособенностях работы Lerna и поделился знаниями намастер-классе. Но как быть состальными? Как быть сновыми разработчиками, которые приходят вкомпанию и вносят свои изменения? Проводить мастер-класс каждый раз не будешь. ВReadMe инструмента, как и внутри нашего монорепозитория, есть инструкция дляработы, но она не всегда помогает. Из-занепонимания случалось следующее:


  • врепозитории обновлялись лишние пакеты;
  • восновной кодовой базе монолита поднято меньше зависимостей, чем должно быть;
  • или наоборот зависимостей поднято больше, чем должно быть.

Кроме того, перед тем, как опубликовать пакет, необходимо обновить длянего changelog. Вбольшинстве случаев он является копипастой, но её необходимо повторить внескольких репозиториях. Дляодного-двух это не проблема, но когда пакетов становится десяток, легко где-то допустить ошибку или забыть добавить запись вchangelog. А это значит, что придётся вносить исправления и ждать, когда завершит свою работу билд CI.


Возникшие проблемы мы решили черезавтоматизацию. Дляэтого написали специальный скрипт, который:


  • находил все зависимые пакеты;
  • поднимал вних dev или latest версию взависимости отпотребности;
  • добавлял changelog всем пакетам;
  • заменял новые версии вpackage.json файле монолита нановые и, вслучае dev пакетов, ещё и публиковал их.

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


Работа CI


Остаётся ещё один вопрос, который хочется подсветить: CI.


Так как репозиторий один, то и все тесты гоняются нанём сразу. Кроме того, появился внутренний инструмент, который позволяет писать компонентные тесты сиспользованием библиотеки Enzyme. Его написали ребята изплатформенной команды Авито и рассказали онём вдокладе Жесть дляJest. Это позволило покрыть сценарии, которые раньше нельзя было проверить. Так, например, появилась возможность проверить вызов попапа приклике на кнопку все характеристики впакете стехническими характеристиками дляавтомобилей.


В результате накаждый пул-реквест прогоняется весь набор имеющихся тестов. Теперь тесты могут дать определённую гарантию того, что приподнятии версии зависимого пакета ничего не сломается. Но есть и минусы: количество пакетов вмонорепозитории растёт, сним растёт и количество тестов. Как следствие, растёт и время их прогона. Приэтом кажется, что нет смысла гонять тесты там, где нет никаких изменений. А значит, можно сократить время выполнения билда вбудущем. Внутренний инструмент продолжает развиваться, и уже сейчас внём появился механизм дляпрогона определённого скоупа тестов. Именно этот механизм и будет использоваться дляуменьшения выборки тестов и сокращения времени выполнения билда.


Итоги и планы


Задва года мы прошли процесс перехода отбольшого количества слабо связанных репозиториев доавтоматизации работы смонорепозиторием черезLerna. Приэтом, есть гарантия того, что всё будет работать корректно благодаря прогону тестов накаждом пул-реквесте. Количество самих пул-реквестов уменьшилось с8-9 вхудшем случае додвух: вмонолит и вмонорепозиторий. Приэтом пул-реквест вмонорепозиторий содержит сразу все изменения.


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

Подробнее..

С чего начинаются тесты

21.10.2020 08:16:04 | Автор: admin

Тестов много не бывает. И речь идёт не только о наращивании их количества (что само по себе, конечно, тоже хорошо) речь идёт о разнообразии самих видов тестов. Даже не напрягая воображение можно вспомнить несколько способов протестировать ваше приложение: Unit-тесты, интеграционные тесты, API-тесты, системные тесты и это не вспоминая о том, что тесты ещё бывают функциональными, нагрузочными, направленными на отказоустойчивость...


Но с чего же начинать писать тесты для новых проектов? Лично для меня, как для программиста, самый интуитивный ответ это Unit-тесты. Однако опрометчиво накидываться на сочинение Unit-тестов может не только оказаться бесполезым занятием, но даже нанести вред в будущей разработке проекта.


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


А можно всех посмотреть?


Я думаю, многие из вас видели ту или иную версию вот этой картинки:



Существуют различные вариации этой картинки может меняться количество слоёв, их название, состав, но суть остаётся неизменной: тестирование программ можно разбить на несколько уровней, и при этом чем выше мы поднимаемся по этим уровням тем дороже и сложнее становится разработка и проведение тестов и, соответственно, количество тестов на уровне N+1 будет неизменно меньше, чем на уровне N.


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


Unit-тесты


В основе пирамиды лежат Unit-тесты (или, в русском варианте, модульные тесты). Unit-тесты направлены на тестирование небольших модулей программы. Зачастую под модулем понимается отдельный класс или даже функция.



Несколько особенностей Unit-тестов:


  1. Подразумевают принцип "белого ящика" то есть эти тесты требуют наличия и понимания исходных кодов программы.
  2. Дёшево стоят, можно наклепать тысячи, если не десятки тысяч Unit-тестов.
  3. Быстро прогоняются.
  4. По своей природе автоматизированы.
  5. Позволяют очень точно локализовывать ошибки можно узнать конкретную функцию/класс, которая работает неправильно.
  6. Плохо подходят для комплексных проверок.

Интеграционные тесты


На следующем уровне пирамиды обычно указываются интеграционные тесты. Интеграционные тесты направлены на тестирование больших обособленных блоков программы и их взаимодействие между собой (опционально). Под блоком может пониматься отдельная библиотека с частью функционала программы, или же просто большой обособленный участок кода, который слишком велик для покрытия обычными Unit-тестами. Если же программа не бьётся на обособленные блоки и имеет монолитную архитектуру, то интеграционные тесты могут прогоняться для всей программы целиком, но при этом программа помещается в "вакуум" никак не общается и не взаимодействует с "внешним миром".



Несколько особенностей интеграционных тестов:


  1. Всё ещё требуют принцип "белого ящика" тестирование блоков подразумевает понимание интерфейса этих блоков, как минимум. Внутреннее устройство модулей в интеграционном тестировании уже не участвует.
  2. Несколько сложнее Unit-тестов, т.к. зачастую блоки требуют много подготовительной работы, прежде чем они смогут "нормально" функционировать.
  3. Чуть сложнее поддаются автоматизации всё зависит от конкретного блока и его устройства/назначения.

API-тесты


Также в пирамиде иногда выделяют API-тесты. Иногда их относят к интеграционным, иногда как отдельный уровень, но сути это не меняет. Если какая-то часть программы имеет чётко выраженный и оформленный API, то можно выстроить тесты, "дергая" этот API и сверяя фактический результат с ожидаемым. Часто такое можно встретить в распределённых приложениях.


Сейчас такой вид тестов получил просто огромное распространение за счёт очень большой популярности REST API. Это очень удобный способ связывать клиент-серверные приложения между собой, и поэтому, конечно, создаётся очень заманчивое желание абстрагироваться от клиента и протестировать только серверную составляющую, дергая за "ниточки" API.


Несколько свойств этого вида тестирования:


  1. Может рассматриваться как подвид интеграционного тестирования.
  2. Требует чётко оформленного и (желательно) документированного API.
  3. Чаще всего нормально поддаётся автоматизации. Если речь идёт о популярном виде API (например, REST) то к вашим услугам большое количество готовых открытых и коммерческих инструментов, которые позволяют автоматизировать такие тесты на раз-два. Если же API нетипичное, то может потребоваться разработать собственную утилиту по вызову этого API и проверке результатов. В любом случае, стоимость автоматизации выше, чем у Unit-тестов.
  4. Позволяет протестировать очень большие самостоятельные компоненты программы и иногда всю программу в целом.

Тем не менее, нужно заметить, что этот вид тестирования возможен только при наличии у программы (или у её компонентов) чётко сформированного API. Что бывает далеко не всегда (например, по соображениям безопасности, или просто наличие API не предусмотрено архитектурой приложения).


Системные тесты


На вершине пирамиды располагаются системные (или, как их иногда называют, end-to-end) тесты. Иногда на вершине пирамиды указывают UI-тесты, но лично я бы не стал выделять этот вид тестов в отдельный уровень. Впрочем, это лишь дело вкуса, потому что UI-тесты можно считать подмножеством системных тестов.



Системные тесты направлены на тестирование всей программы в целом, с учётом окружения, в которой программе предстоит работать. Это уточнение очень важное, ведь программа редко когда может работать "сама по себе". Программа работает на одном или нескольких (в случае распределенных приложений) конкретных компьютерах. И на разных компьютерах (в разных условиях) тестируемая программа может повести себя по-разному. Например, клиент-серверное приложение может работать замечательно в обычной сети, но при этом может оказаться неработоспособным при наличии между клиентом и сервером маршрутизатора с настроенным NAT.


Такой вид тестов является самым дорогим, самым сложным и самым трудноавматизируемым видом тестов. Зачастую системные тесты настолько сложно автоматизировать, что их и вовсе прогоняют вручную, что ещё больше увеличивает их стоимость. При этом этот вид тестов обладает одним неоспоримым и важнейшим преимуществом: это тестирование программы в том виде, в котором её увидит пользователь. Больше того, системные тесты позволяют даже воспроизвести условия различных пользователей, чтобы убедиться, что у всех пользователей всё работает хорошо.


Несколько заметок о системных тестах:


  1. Предполагают тестирование по методу "черного ящика". Никаких знаний об исходных кодах или особенностях работы программы только UI-тесты.
  2. Наиболее комплексный вид тестирования даже распределенные приложения тестируются вместе, а не по отдельности.
  3. Даёт наибольшую степень уверенности, что протестированные фичи действительно будут работать у конечных пользователей.
  4. Самый дорогой вид тестов.
  5. Долго или очень долго прогоняются.

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


Что ж, ликбез в теорию я заканчиваю, и перехожу к самой интересной части какой вид тестов лучше писать в первую очередь?


Не спешите с Unit-тестами


Я думаю, что рисунок с пирамидой тестов создаёт обманчивое впечатление. Этот рисунок призван лишь продемонстрировать распределение количества тестов по разным уровням в зависимости от их стоимости. Но вместо этого он создаёт ощущение, что тесты более высокого уровня как бы "базируются" на тестах более низкого уровня. И, соответственно, может показаться, что "пока не разберусь с Unit-тестами, об интеграционных и говорить нечего. Ну а до системных хорошо если вообще доберёмся". И я считаю, что это в корне неверная позиция.


Представим ситуацию, что вы разрабатываете совершенно новое приложение. Неважно, как именно вы его разрабатываете на основе четко сформированных требований или же "по наитию". В какой-то момент времени вам (надеюсь) захочется написать тесты. Это может случиться как только у вас получится что-то работающее, или же тесты окажутся вообще вашим самым первым шагом если вы придерживаетесь концепции TDD (Test Driven Development). Неважно когда, но этот момент настанет. И о каких же тестах вы подумаете в первую очередь?


Лично я, как разработчик, всегда думаю в первую очередь о Unit-тестах! А почему бы и нет? Ведь для меня программа это, в первую очередь, исходный код. Если я сам пишу код и знаю, как он работает/должен работать, то для меня самый логичный первый шаг покрыть его тестами. Больше того, я уже знаю, как это делается, я делал это тысячу раз, это зона моего комфорта. Поэтому я с чувством выполнения великой миссии (тесты это же хорошо!) начинаю стандартную возню с Unit-тестами: скачиваю свой любимый фреймворк, продумываю абстрактные классы вместе с интерфейсами, занимаюсь mock-ированием объектов И радуюсь, какой я молодец.


И тут я загоняю себя в две потенциально-опасные ситуации. Посмотрим на первую проблему.


Кто может быть первым кандидатом на Unit-тесты? Лично я бы начал с обособленных участков кода и классов, которые выглядят вполне самостоятельными. Например, я решил, что для моего проекта мне понадобится самописная хеш-таблица. Это же отличный кандидат на покрытие Unit-тестами! Интерфейс понятен и меняться не будет, так что написать тесты сам бог велел. И вот я воодушевлённо трачу своё рабочее время, накидывая десятки тестов. Может быть, я даже выловлю несколько багов в своём коде (боже, как я хорош, как мощны мои тесты) и и спустя два месяца я вдруг понимаю, что хеш-таблица мне вовсе не нужна, лучше бы её заменить базой данных. И все мои рабочие часы на Unit-тесты (и выловленные баги) летят в помойку.


Обидно? Ну что ж, с кем не бывает, ничего страшного. Это ведь не повод отказываться от Unit-тестов, верно? Сделаем заметку и рассмотрим вторую опасную ситуацию.


Отловив все очевидные участки кода, которые можно покрыть Unit-тестами, вы вдруг понимаете, что вы покрыли всего 10% кода (ну нет у вас сейчас четких обособленных модулей с внятными интерфейсами на такой стадии проекта). Тогда вы начинаете беспощадно рефакторить свой код выделяете абстрактные классы, выстраиваете зону ответственности между модулями, инкапсулируете, инкапсулируете, инкапсулируете занимаетесь, в общем-то, полезными делами, честно говоря. Ну и каждый свой успех отмечаете очередной порцией Unit-тестов, ведь ради них, родимых, всё и затевается!


Спустя пару недель работы вы получаете 60% покрытого тестами кода. У вас появилась сложная иерархия классов, mock-объекты, а общее количество Unit-тестов перевалило за 100500. Всё хорошо, так ведь?


Всё хорошо ровно до тех пор, пока вы не увидите, что вашу архитектуру можно было бы улучшить (а с развитием проектов, особенно новых, такие наблюдения случаются регулярно). И вместо того, чтобы смело ринуться в дебри рефакторинга, вы начинаете грустно думать о 100500 Unit-тестах и о том, как теперь вам придётся их переделывать. Вы становитесь заложником своих собственных Unit-тестов, которые начинают сковывать вашу гибкость в принятии архитектурных решений. И выбор у вас получается так себе. Либо решиться на рефакторинг и спустить в унитаз всё время, потраченное на Unit-тесты, либо (ещё хуже) оставить всё как есть, и затем бороться с не самой удачной (как вы теперь понимаете) архитектурой.


Звучит так, как будто я просто персонально терпеть не могу Unit-тесты и пытаюсь отговорить вас от их использования, так?


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


Лучше спешите с системными тестами!


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



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


Как я уже упоминал выше, системные тесты это тесты программы в целом. При этом программа представляется именно в том виде, в котором её увидит пользователь. Фактически, системные тесты заставляют нас взглянуть на программу как на законченный продукт (хоть он таким сейчас и не является). Если другими словами, то вместо подхода от "от частного к общему" мы начинаем писать тесты "от общего к частному". А это позволяет нам убить сразу двух зайцев:


  1. Прорабатывая системные тесты, мы формализуем и фиксируем требования к программе в виде скриптов, которые или проходят или нет. Соответственно, будет гораздо меньше споров о том, когда фичу можно считать законченной.
  2. Системные тесты позволяют очень четко визуализировать и разложить по полочкам то, как наша программа будет выглядеть для конечного пользователя. Это уже ценно само по себе, но также позволяет обнаружить на ранних этапах несостыковки в требованиях (а они всегда есть). Также становится понятным, какие моменты требуют дальнейшей проработки.

Звучит неплохо, не правда ли? Причём, системные тесты обладают ещё рядом очень приятных бонусов:


  1. В условиях зафиксированных требований к программе системные тесты не могут сильно меняться. Это возможно благодаря самой природе системных тестов: они рассматривают программу как "черный ящик" без какой-либо привязки к архитектуре и особенностям реализации. А это значит, что вы можете свободно менять архитектуру своей программы по первому требованию, и никакие тесты менять не придется! Ну, разве что, немного подкорректировать если у вас добавилась новая зависимость или что-то в таком духе.
  2. Системные тесты могут писать аналитики или даже тестировщики не отнимая, таким образом, ценное время программистов. Также это позволяет аналитикам дать программистам более четкое понимание, что именно они хотят увидеть в программе. Программистам лишь останется добиться того, чтобы тесты проходили, не ломая голову над вопросом "чего же от меня хотят".
  3. Системные тесты это очень комплексный вид тестов. Если ваша программа проходит сложный комплексный тест то вы уже с довольно высокой долей вероятности можете быть уверены, что "в целом, наверное, все компоненты нормально работают". В Unit-тестах наоборот уверенность в одном классе не дает абсолютно никакой уверенности в работоспособности программы в целом.

Остаётся только одна проблема: системные тесты с трудом поддаются автоматизации. Возможно, это одна из причин, почему сейчас системные автотесты или оставляют "на потом", или вообще ограничиваются ручным тестированием.


Впрочем, сейчас на этом фронте не всё так уж и плохо существует очень много коммерческих решений, которые позволяют в том или ином виде решить эту проблему: Testcomplete, Squish, Ranorex, Eggplant это лишь самые известные примеры таких систем. У всех у них есть свои достоинства и недостатки, но в целом со своей задачей по автоматизации системных тестов они справляются (хоть и стоят очень немалых денег).


А вот среди бесплатных решений выбора особо нет. По крайней мере не было.


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


А что же другие тесты?


Заметьте, что я сосредоточился на том, что стоит начинать с системных тестов, потому что это даёт определенные неплохие бонусы. Но это отнюдь не означает, что стоит пренебрегать другими видами тестов.


В самом деле, системные тесты дают неплохое представление о том, что программа в целом работает, но при этом они не ограничивают вашу свободу при работе скальпелем в вашем проекте. Но это не отменяет того факта, что системные тесты всё равно остаются довольно тяжеловесными (даже с учётом автоматизации) и их действительно невозможно клепать с той же легкостью и скоростью, как API-тесты или, тем более, Unit-тесты.


В развитием проекта вы обнаружите, что вас уже не устраивает только проверка "в целом всё работает". Со временем архитектура вашего нового приложения неизбежно "устаканится", крупных изменений будет всё меньше и меньше. В какой-то момент вы поймёте, что вы хотите навесить побольше проверок на какой-нибудь компонент (потому что он уже точно никуда из проекта не денется, и его интерфейс точно проработан), или даже на конкретный класс А для особо важных участков кода и вовсе желательно проработать все возможные ветвления. Или же вам очень интересно, как поведёт себя программа при непосредственном обращении к API. Чувствуете, да? Вот и другие тесты снова в деле!


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


  1. В самом начале, когда проект активного развивается с нулевого состояния, необходимо писать только системные тесты. Тестов нужно написать столько, чтобы у вас была четкая уверенность, что "в целом моя программа работает нормально". Это будет отличный базис для дальнейшей работы.
  2. По мере развития проекта и "устаканивания" его архитектуры и основных компонентов можно добавлять интеграционные тесты. Если у проекта появилось чётко выраженное и стабильное API нужно начинать писать API-тесты.
  3. Наконец, для особо важных изолированных участков кода, от правильной работы которых зависит очень многое, можно написать Unit-тесты.
  4. Помнить, что из любого правила есть исключения. При возникновении достаточно веских объективных причин повышайте приоритет интеграционных и Unit-тестов. Не нужно откладывать разработку тестов более низкого уровня, если вы в них действительно нуждаетесь здесь и сейчас.

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


Итоги


Вроде бы про разработку "от общего к частному" уже давным давно всё известно вдоль и поперёк, но при этом тесты всё равно упорно составляются "от частного к общему". Возможно, это дело привычки, а возможно в том, что так просто удобнее ведь написать двадцать Unit-тестов всегда проще, чем пару системных тестов.


Но по мере развития инструментов для автоматизации системных тестов перспектива сходу автоматизировать end-to-end тесты уже не кажется такой уж пугающей. Возможно, вам понравится разрабатывать тесты "сверху вниз" ведь так их можно разрабатывать ровно по мере их надобности.

Подробнее..

Перевод Как протестировать блокноты Jupyter с помощью pytest и nbmake

20.05.2021 16:23:11 | Автор: admin

Файлы блокнотов Jupyter, в смысле количества одного из самых быстрорастущих типов файлов на Github, предоставляют простой интерфейс для итераций при решении визуальных задач, будь то анализ наборов данных или написание документов с большим объёмом кода. Однако популярность блокнотов Jupyter сопровождается проблемами: в репозитории накапливается большое количество файлов ipynb, многие из которых находятся в нерабочем состоянии. В результате другим людям трудно повторно запустить или даже понять ваши блокноты. В этом руководстве рассказывается, как для автоматизации сквозного (end-to-end) тестирования блокнотов можно воспользоваться плагином pytest nbmake.

К старту флагманского курса о Data Science области, в которой блокноты Jupyter незаменимы делимся переводом статьи из блога CI Semaphore о том, как при помощи Semaphore проверить, что ваши блокноты Jupyter находятся в рабочем состоянии и для этого больше не запускать блокноты вручную.


Предварительные требования

Это руководство предполагает владение основными навыками тестирования проектов на Python, о них рассказывается в статьеНепрерывная интеграция и развёртывание на Python с нуля. Прежде чем продолжить, пожалуйста, убедитесь, что вы знакомы с основами и на вашем компьютере установлен набор инструментов Python 3, таких как pip + virtualenv.

Демонстрационное приложение

Обычно проекты Python содержат папки с файлами блокнотов с расширением .ipynb, это может быть:

  • код доказательства концепции;

  • документация с примерами применения API;

  • длинный научный туториал.

В этой статье мы разберём, как автоматизировать простые сквозные тесты некоторых блокнотов, содержащих упражнения на Python. Благодарим pytudes за предоставленные для нашего примера материалы; воспользуемся этим примером проекта, не стесняйтесь делать форк и клонировать его с GitHub:

fig:fig:

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

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

Локальное тестирование блокнота

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

Давайте начнём автоматизировать этот процесс в вашей среде разработки; первым шагом в автоматизации станет nbmake. Nbmake это пакет python и плагин к pytest. Он разработан автором этого руководства и используется известными научными организациями, такими как Dask, Quansight и Kitware. Вы можете установить nbmake с помощью pip:

pip install nbmake==0.5

Перед первым тестированием блокнотов давайте проверим, всё ли правильно настроено, указав pytest просто собрать (но не запускать) все тест-кейсы для блокнотов.

 pytest --collect-only --nbmake "./ipynb" ================================ test session starts =================================platform darwin -- Python 3.8.2, pytest-6.2.4, py-1.10.0, pluggy-0.13.1rootdir: /Users/a/git/alex-treebeard/semaphore-demo-python-jupyter-notebooksplugins: nbmake-0.5collected 3 items           ============================= 3 tests collected in 0.01s =============================

Мы видим, что pytest собрал несколько элементов.

Примечание: если вы получаете сообщение unrecognized arguments: --nbmake, оно означает, что плагин nbmake не установлен. Такое может произойти, если ваш CLI вызывает двоичный файл pytest за пределами текущей виртуальной среды. Проверьте, где находится ваш двоичный файл pytest, с помощью команды which pytest.

Теперь, когда мы проверили, что nbmake и pytest видят ваши блокноты и работают вместе, давайте выполним настоящие тесты:

 pytest --nbmake "./ipynb"================================ test session starts =================================platform darwin -- Python 3.8.2, pytest-6.2.4, py-1.10.0, pluggy-0.13.1rootdir: /Users/a/git/alex-treebeard/semaphore-demo-python-jupyter-notebooksplugins: nbmake-0.5collected 3 items                                                                    ipynb/Boggle.ipynb .                                                           [ 33%]ipynb/Cheryl-and-Eve.ipynb .                                                   [ 66%]ipynb/Differentiation.ipynb .                                                  [100%]================================= 3 passed in 37.65s =================================

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

Игнорирование ожидаемых ошибок в блокноте

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

К счастью, чтобы указать nbmake, что такие блокноты нужно игнорировать и продолжать работу после возникновения ошибок, в метаданные нашего блокнота мы можем поместить директивы. Возможно, вы раньше не использовали метаданные блокнота, поэтому самое время упомянуть, что, несмотря на их расширение ipynb, блокноты это просто JSON-файлы. Чтобы добиться от них нового поведения, добавьте новые поля:

  • откройте файл .ipynb в простом текстовом редакторе, например Sublime;

  • в метаданных блокнота найдите поле kernelspec;

  • добавьте объект execution в качестве родственного элемента kernelspec.

Должно получиться что-то вроде этого:

{  "cells": [ ... ],  "metadata": {    "kernelspec": { ... },    "execution": {      "allow_errors": true,      "timeout": 300    }  }}

Теперь можно перезапустить блокнот, чтобы проверить, что JSON валиден, а ошибки игнорируются.

Ускорение тестов с помощью pytest-xdist

В крупных проектах может быть много блокнотов, каждый из которых требует много времени на установку пакетов, извлечение данных из сети и выполнение анализа. Если ваши тесты занимают более нескольких секунд, стоит проверить, как на время выполнения повлияет распараллеливание. Сделать это можно с помощью другого плагина pytest pytest-xdist. Сначала установите пакет xdist. Это похожий на nbmake плагин pytest, он добавит новые параметры командной строки:

pip install pytest-xdist

Запустите команду ниже с количеством рабочих процессов, равным auto:

pytest --nbmake -n=auto "./ipynb"

Запись выполненных блокнотов обратно в репозиторий

По умолчанию тесты доступны только для чтения, то есть ваш файл ipynb на диске остаётся неизменным. Обычно это хорошее значение по умолчанию, потому что во время выполнения блокнота ваш редактор может быть открыт. Однако в некоторых ситуациях может потребоваться сохранить результаты теста на диске. Например, если вам нужно:

  • отладить неработающие блокноты путём просмотра выходных данных;

  • создать коммит в вашем репозитории с блокнотами в воспроизводимом состоянии;

  • встроить выполненные блокноты в сайт с документацией при помощи nbsphinx или jupyter book.

Мы можем направить nbmake на сохранение выполненных блокнотов на диск с помощью флага overwrite:

pytest --nbmake --overwrite "./ipynb"

Исключение блокнотов из тестов

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

pytest --nbmake docs --overwrite --ignore=docs/landing-page.ipynb

Примечание: это не сработает, если вы выбираете все блокноты с помощью шаблона поиска, например (*ipynb), вручную переопределяющего флаги игнорирования pytest.

Автоматизация тестирования блокнотов на Semaphore CI

С помощью вышеописанных методов можно создать автоматизированный процесс тестирования с использованием непрерывной интеграции (CI) Semaphore. Ключ здесь прагматизм: нужно найти способ протестировать большую часть ваших блокнотов и проигнорировать сложные блокноты; это хороший шаг к улучшению качества.

Начните с создания содержащего ваши блокноты проекта для репозитория. Выберите Choose repository:

Затем подключите Semaphore к репозиторию с вашими блокнотами:

Пока пропустите Add People, чтобы мы могли настроить рабочий процесс с нуля (даже если вы работаете с деморепозиторием). Semaphore предоставляет некоторую начальную конфигурацию, настроим её перед запуском:

Создайте простой рабочий процесс в один блок; ниже о процессе в деталях:

  1. Названием блока будет Test.

  2. Названием задачи Test Notebooks.

  3. В поле Commands введите команды ниже:

checkoutcache restorepip install -r requirements.txtpip install nbmake pytest-xdistcache storepytest --nbmake -n=auto ./ipynb

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

  1. checkout клонирует репозиторий с GitHub;

  2. cache restore загружает зависимости Python из кэша Semaphore. Это ускоряет процесс установки;

  3. pip устанавливает зависимости и инструменты;

  4. cache store сохраняет загруженные зависимости обратно в кэш;

  5. pytest запускает тесты nbmake.

Теперь мы можем запустить рабочий процесс. Не беспокойтесь, если конвейер выйдет из строя: далее мы рассмотрим распространённые проблемы.

Конвейер должен заработать сразу же:

Устранение некоторых распространённых ошибок

Добавление отсутствующего ядра Jupyter в среду CI

Если вы используете имя ядра, отличное от имени по умолчанию python3, то при выполнении ноутбуков в свежей среде CI увидите сообщение об ошибке: Error - No such kernel: 'mycustomkernel'. Чтобы установить пользовательское ядро, воспользуйтесь командой ipykernel:

python -m ipykernel install --user --name mycustomkernel

Если в своих блокнотах вы работаете с другим языком, например С++, ваш процесс установки ядра может быть другим.

Добавление недостающих секретов в среду CI

В некоторых случаях ваш блокнот получает данные от API, требующих токена или аутентифицированного CLI. Всё, что работает в вашей среде разработки, должно работать и на Semaphore. Чтобы увидеть, как настроить секреты, сначала посмотрите этот пост. Как только вы установили секреты в Semaphore, чтобы прочитать их из переменной среды в средах CI, вам может потребоваться настроить блокнот.

Добавление недостающих зависимостей в среду CI

Стек Data Science на Python часто требует установки собственных библиотек. Если вы работаете с CONDA, вполне вероятно, что они будут присутствовать в вашем нормальном процессе установки. Если же вы используете стандартные библиотеки Python, их присутствие немного менее вероятно.

Если вы пытаетесь установить необходимые вам библиотеки, посмотрите на статью о создании образа docker в CI. С ним тестирование упрощается, и по сравнению со стандартными средами Semaphore этот подход стабильнее во времени.

Пожалуйста, помните совет о прагматизме; 90 % полезности часто можно достичь за 10 % времени. Следование совету может привести к компромиссам, таким как игнорирование блокнотов, на которых запускаются требующие GPU модели ML.

Заключение

В этом руководстве показано, как можно автоматизировать тестирование блокнотов Jupyter, чтобы поддерживать их воспроизводимость. Блокноты оказались эффективным инструментом для построения технических нарративов. Однако из-за новизны некоторые команды разработчиков программного обеспечения исключают их использование до тех пор, пока не появятся более чёткие процессы для тестирования, ревью и повторного использования их содержимого.

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

  • для удаления громоздких выходных данных блокнота перед коммитом запустите pre-commit и nbstripout;

  • для компиляции ваших блокнотов в красивый сайт с документацией используйте jupyter book;

  • для просмотра блокнотов в пул-реквестах используйте ReviewNB.

Действительно, процессы в разработке ПО и в научных исследованих всё дальше уходят с локальных компьютеров на арендуемые мощности самого разного рода, в том числе потому, что требуют всё больших ресурсов. То же касается и растущих объёмов данных, работа с которыми преобразилась в несколько смежных, но очень разных областей; среди них центральное место занимает Data Science. Если вам интересна эта сфера, вы можете присмотреться к нашему курсу Data Science, итог которого это 16 проектов, то есть 2-3 года постоянного самостоятельного изучения науки о данных.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Теперь YouTrack интегрируется с GitLab CICD

28.05.2021 14:21:34 | Автор: admin

Привет, Хабр!

На связи команда JetBrains YouTrack, и у нас для вас новый релиз! Мы дополнили интеграцию с GitLab теперь YouTrack не только отслеживает коммиты и merge-реквесты, но и поддерживает интеграцию с GitLab CI/CD. А это значит, что задачи в YouTrack смогут обновляться автоматически по результатам автоматизированных сборок в GitLab CI/CD. Также мы дополнили релиз интересными улучшениями для работы с задачами. За подробностями добро пожаловать под кат!

Об интеграции с GitLab CI/CD что это и зачем

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

Как это работает? CI/CD периодически забирает новый код из системы контроля версий (VCS), собирает проект, прогоняет автотесты и разворачивает собранную и протестированную версию, например на сервере, где тестировщики смогут провести остальные этапы тестирования. Если что-то упало, CI/CD сообщит об этом кому нужно, например техлиду проекта или разработчику, который сделал злосчастный коммит.

YouTrack уже давно позволяет интегрировать в процесс управления задачами TeamCity и Jenkins, а теперь к ним присоединился и GitLab CI/CD.

GitLab CI/CD работает с конвейерами (пайплайнами), каждый из которых состоит из ряда заданий (jobs). При появлении изменений в коде GitLab CI/CD выполняет соответствующие задания из пайплайна, чтобы убедиться, что новый код ничего не сломал. Если задание в пайплайне выполнено успешно, GitLab делится этой радостью с YouTrack, который в свою очередь обновляет нужные задачи.

Как именно обновляет? Как скажете! Например, YouTrack может автоматически помечать задачи, упомянутые в сообщении коммита, как завершенные и прописывать в задаче номер пайплайна и ссылку на него. Как обычно, вы можете завязать на интеграцию рабочие процессы (например, указать, чтобы при изменении значения поля Fixed build на странице задачи появлялся комментарий о том, что фикс доступен в продакшене).

Что еще нового?

Мы внесли ряд улучшений в YouTrack Lite и Classic. В YouTrack Lite появилась функция Похожие задачи, которая позволяет избежать дублирования задач. Когда при создании задачи вы вводите ее название, YouTrack ищет задачи со схожим названием и предлагает вам просмотреть их и убедиться, что новая задача их не дублирует. В YouTrack Classic мы добавили удобный текстовый редактор такой же, как в базе знаний и в YouTrack Lite. Теперь вы можете одним щелчком переключаться между режимом разметки и режимом WYSIWYG, встраивать мультимедийные объекты, создавать таблицы и контрольные списки.

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

Лучше один раз увидеть, чем сто раз прочитать. Напомню, что YouTrack со всеми его новшествами можно попробовать бесплатно. Мы будем рады вашей обратной связи!

Команда YouTrack

Подробнее..

Фирма 1С приглашает вас принять участие в нашей первой конференции для системных разработчиков

15.01.2021 12:16:15 | Автор: admin
Всем добрый день!

Фирма 1С приглашает вас принять участие в нашей первой конференции для системных
разработчиков, которая пройдет 23 января в онлайн-формате.

Наверное, вы сейчас думаете да 1С это ж бухгалтерия, какая системная разработка?

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

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

Или зачем нам вдруг понадобилось использовать NoSQL DB при разработке собственной IDE? (Да-да, у нас есть собственная IDE, да не одна, а целых три!)

Чем же мы на самом деле занимаемся
Если же говорить, чем же мы на самом деле занимаемся наш ключевой продукт это фреймворк для создания бизнес-приложений 1С: Предприятие. Написан он на C++, Java, и JS. Умеет работать на разных платформах (Windows, Linux, MacOS, Android, iOS), в вебе, поддерживает разные СУБД и многое другое. Да и не просто работать, а инкапсулировать особенности каждой СУБД и выглядеть одинаково на разных платформах (интерфейсы генерируются автоматически про это, кстати, будет отдельный доклад).

Платформа 1С: Предприятие, на самом деле, двойственна она объединяет в себе как инструменты разработки, так и среду исполнения в различных вариантах (локальном, клиент-серверном, кластерном, мобильном, облачном, распределенном). Да, кстати, про облака тоже будет без них сейчас никуда.

Почему мы вдруг решили, что нам есть, что рассказать миру? Потому что более 5 млн.
пользователей работают в приложениях, написанных на платформе 1С: Предприятие, ежедневно, и не просто разок запустить а целый рабочий день. И нам пришлось решить много сложных системных задач, чтобы добиться этого!

Еще немного спойлеров:

  • Расскажем, зачем нам понадобился GraalVM
  • Как заставить Xtext эффективно работать с миллионами строк программного кода?

Так что приходите, очень ждем!
Программа конференции и регистрация по ссылке.
Ну и на сладкое какая конференция без машинного обучения? Расскажем о нашем собственном механизме распознавания документов (и покажем детали)!
Подробнее..

Мир без DevOps. Каким бы он был?

28.07.2020 16:18:22 | Автор: admin

Вспомним классику.


Разработчики с трудом выкатывают фичи раз в год. Зато админы довольны и радостны им больше не нужно уходить с работы, они теперь работают круглосуточно, и руководство их ласково называет нянечки для разрабов. Технологии начинают откатываться. Отладка требует сотни передач из отдела в отдел все с огромным энтузиазмом перекидывают друг другу дохлую свинью через забор. Даже свинья улыбается. Долгое ожидание сервера под проект запросил сервер, получил посмертно, за заслуги перед компанией. Баги в продакшене с полной уверенностью рассчитывают увидеть XXII век. SLA 50% и седые до прозрачной белизны владельцы бизнеса. Упал сервис не проблема, подождём часок или два, пока поднимется. Универсальные инженеры на грани психоза на столе у каждого по две полупустых баночки бензодиазепиновых транквилизаторов и пачка SSRI-антидепрессантов.


Вздрогнули? И с лёгким сердцем обратно в нормальный мир, где есть DevOps-философия и DevOps-инструменты, как часть неё.


19-21 августа пройдёт онлайн-интенсив Слёрм DevOps: Tools&Cheats. Мы покажем IDDQD из мира DevOps.



Да есть книги и мануалы одни дают теорию, другие информацию. Но только на конференциях и интенсивах можно получить практику из первых рук. Именно практику, а не пересказ тех самых мануалов.


Слёрм DevOps: Tools&Cheats:


  • за 3 дня получить представление об основных инструментах;
  • после прохождения курса можно сразу внедрять практики у себя на работе;
  • много, даже очень много практических заданий;
  • спикеры практикующие DevOps-инженеры и разработчики с многолетним опытом;
  • никто не будет отнимать время объемными лекциями по философии DevOps, у нас упор на инструменты и практику.

С программой курса и спикерами вы можете ознакомиться и познакомиться на странице интенсива.



Поговорим откровенно? Почему мы создали этот курс? Потому что нас тоже бесит:


  • что курсы для практиков ведут теоретики;
  • что решением проблем считают не подход, а должность;
  • что 80% курсов по девопсу рассказывают о концепции и философии. А инструменты где? Чем гвозди забивать, микроскопом или лучше Macbook Pro?
  • бесит, когда к концу обучения забыл, что было в начале, а результатов надо ждать от 6 до 8 месяцев.

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


За эти три дня вы научитесь основным DevOps-практикам, которые позволят:


  • организовать командную работу с Git;
  • автоматизировать рутинные операции;
  • настроить мониторинг и интегрировать его с мессенджерами;
  • развернуть серверы, используя подход Infrastructure as Code;
  • обеспечить процесс CI;
  • И ещё немного практических читов из реальной работы.

Слёрм DevOps пройдет с 19 по 21 августа 2020. Каждый день начинаем в 10:00 и заканчиваем в 19:00, с перерывами на чай и обед.


Инструменты DevOps + IDDQD + IDKFA и за работу. И пусть кто-то только попробует помешать.

Подробнее..

Инфраструктура как код в Авито уроки, которые мы извлекли

18.08.2020 14:15:47 | Автор: admin

Привет, Хабр! Меня зовут Саша Козлов, я занимаюсь разработкой инфраструктуры и системным администрированием вАвито последние три споловиной года. Я расскажу, как мы масштабировали и модернизировали современем нашу работу синфраструктурным кодом и вывели её накачественно новый уровень.


Мы отвечаем заполный цикл управления оборудованием: отзакупки и монтажа вДЦ додоставки доконечного потребителя. Речь пойдёт обуроках, которые мы вынесли запоследние несколько лет, работая стысячей единиц оборудования и несколькими тысячами единиц конфигурирования.



Речь пойдёт обинструментах первого поколения IaC, таких как Ansible, Chef, Salt, Puppet. Если вы имеете дело сon-premises инфраструктурой, и увас нет своего облака навиртуализации, то, скорее всего, вы уже используете один изэтих инструментов.


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


Хорошие практики важнее выбора правильного инструмента


Напервый взгляд, инструменты управления инфраструктурой очень разные. Некоторые требуют, чтобы нанодах был запущен специальный агент. Где-то используется push-модель, где-то pull, но впринципе ничего не мешает запускать ansible накаждой машине покрону и получить pull-конфигурации. Содной стороны Python, Jinja-шаблоны и YAML-программирование, сдругой DSL и Ruby. Многие инструменты включают всвою экосистему дополнительные компоненты: дашборды, хранилище конфигурации вроде PuppetDB, централизованный компонент, который хранит и распространяет навсе ноды ваш инфраструктурный код.


Слюбым инструментом подобного рода не получится работать синфраструктурным кодом ровно так же, как работает скодом разработчик сервиса. Далеко не все изменения откатываются через git revert, сама выкатка этих изменений не происходит одновременно навсей инфраструктуре, а применяется постепенно. Конфигурация влюбом случае остаётся мутабельной, а это значит, что всё равно придётся держать вголове текущее состояние машины. А А не то же самое, что 0 А. Многие такие особенности приходится учитывать.


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


  • проведении статического анализа и линтинга кода, соблюдении стиля кодирования;
  • обеспечении возможности легко тестировать код и уменьшении цикла обратной связи;
  • запуске тестов наCI-системе, чтобы код попадал вмастер только после успешных билдов;
  • уменьшении связанности кода засчёт версионирования модулей и более контролируемого применения изменений винфраструктуре;
  • разработке тулинга, который поощряет разработчика использовать практики, описанные выше;
  • упрощении наливки машины снуля дляуменьшения Configuration Drift.

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


Определите границы применимости инструмента


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


Puppet очень гибок, местами даже слишком. Он впостоянном цикле приводит состояние инфраструктуры кописанному в коде виду, т.к. использует pull-модель. Как следствие этого недостаточно хорошую обратную связь и задержку при применении изменений. По умолчанию конфигурация применяется раз в 30минут, поэтому длязадач, требующих более динамичного управления, Puppet не подходит. Кроме этого, внём нет event-driven автоматизации, как вSalt, что также ограничивает область его применения.


Обограничениях инструментов вроде мутабельности инфраструктуры и отсутствия гарантий отката инфракода я упомянул выше, сними приходится считаться. Поскольку применять их мы собирались длянастройки железных серверов и stateful-контейнеров, мы не рассчитывали, что сможем всякий раз применять конфигурацию счистого состояния. Хотя такую возможность мы себе обеспечили.


Для себя мы определили границы так: применяем Puppet дляконфигурирования железных нод и stateful-контейнеров, но не используем его длядеплоя сервисов, конфигурации рантайма инфраструктурных сервисов и других быстро меняющихся вещей. Например, мы постепенно отходим отуправления DNS-записями через Puppet, который сложился унас исторически. Мы хотим, чтобы управление было более динамическим, поэтому этим занимается инфраструктурный сервис, предоставляющий свой API.


Правильный выбор структуры кода и уменьшение связанности кода


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


Поэтому мы выделили основные сущности: control repo и модули. Каждая находится вотдельном git-репозитории. Сами тут ничего особенно не придумали, просто обратились клучшим практикам дляPuppet-кода, которые описаны встатье "The roles and profiles method".


Control repo это репозиторий синфраструктурным кодом. Внём находится тот код, который выкатывается через CI-систему напаппет-сервер и применяется намашинах. Роль это некоторая типовая конфигурация, способ сгруппировать машины содинаковыми настройками. Это самый высокоуровневый слой абстракции условно, ответ навопрос чем занимается эта машина?. Примеры ролей: k8s-нода кластера Х, нода Kafka встейджинг окружении дляшины данных, ClickHouse-нода и т.п.


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


Роли и профили описываются вcontrol repo, а модули подключаются внеё как внешние зависимости и применяются внутри профилей или ролей.


Модуль это подключаемая библиотека, код, который занимается настройкой определённого инфраструктурного компонента, как правило переиспользуемый. Модули релизятся отдельно отcontrol repo, версионируются поsemver и подключаются как зависимости. Унас сейчас порядка 50 модулей: модуль дляработы ссекретами, настройки различных БД, конфигурирования кластеров Kubernetes и другие.


Вопрос, как структурировать код, насамом деле не очень прост в случае сPuppet. Единственно правильного ответа нанего нет. Далеко не всегда ясно, что должно считаться одной ролью, а вкаких случаях профиль нужно пилить нанесколько. Нужно ли сразу делить код намодули, или можно допоры довремени складывать всё вcontrol repo?


Здесь всё зависит отразмера инфраструктуры, её разнородности и количества инженеров, которые занимаются разработкой инфракода. Дляначала вполне подойдёт просто иметь control repo и весь код писать вней, организуя его впрофили. Унас вАвито инфраструктурой занимается несколько команд, длякаждой важны разные вещи. Одним важнее стабильность, а не скорость внесения изменений, поэтому они обложили код кучей тестов. Другим не подошла стандартная схема тестирования вDocker, и пришлось настроить свою. Поэтому унас несколько control repo, поодной натакую команду. А чтобы можно было переиспользовать решения и не дублировать код, мы пишем модули.


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



А ещё на своём Гитхаб-аккаунте мы поделились шаблоном модуля и control repo, который используем усебя. Вшаблонах можно посмотреть пример того, как организовать код, а ещё там есть инструменты, которые нужны длязапуска всех видов тестов:



Используйте External Node Classifier вместо регулярных выражений


Ну хорошо, есть роли, профили и модули но как именно определяется то, какой код накакой машине выполнять?


Достаточно долго мы использовали node definitions и регулярные выражения, чтобы определять то, какие машины каким кодом настраиваем. Такой подход нормально работает нанебольшой инфраструктуре, но помере её роста вы скорее всего получите что-то похожее на это:


node /^avi-ceph(2[1-9]|3[0-9]|4[0-9]|5[0-9]|6[0-9]|7[0-9]|8[0-9]|9[0-9])/ {...}

Одна неправильно закрытая скобка тут может привести кполному краху. Поиск потакому коду не работает невозможно быстро разобраться, какой код выполняется наотдельно взятой машине. Вобщем, такой подход казался разумным вначале, но современем оказался неудачным. Дляпривязки машин кнаписанным ролям Puppetlabs предлагает использовать External Node Classifier.


External Node Classifier это компонент, который хранит всебе то, какую роль следует применить ккаждой ноде. Он даёт возможность винфракоде описывать только роли, а логику привязки ролей кконкретным машинам вынести вовнешнюю систему. Навход ENC принимает имя ноды и отдаёт некий набор параметров, которые вкоде становятся доступны как top-scope variables. Вкаждой control repo есть примерно такой код, который обеспечивает привязку ноды кроли, и это единственное место, где используется node definition:


node default {  include base # применяем базовый слой конфигурации, общий для всех control repo  if $::role != '' {    notify{ "Node ${::fqdn} has role ${::role}": loglevel => info }    include "role::${role}"  } else {    notify{ "Node ${::fqdn} has no role": loglevel => warning }  }}

Вкачестве ENC может выступать любая система, ведь логику получения и формирования ответа вы пишете сами. Такой системой внашем случае стала CMDB, внутренняя система учёта оборудования и его комплектующих. Наш CMDB основан наnetbox отDigital Ocean, сильно доработанном поднаши нужды. Он плотно интегрирован сrazor, системой провижнинга железа, и умеет собирать всевозможные данные ожелезе, которое установлено вдата-центре.


Дляподготовки сервера кработе винтерфейсе CMDB мы указываем нужный паппет-сервер и роль, отправляем сервер напереналивку и через 15-20минут получаем готовый кработе сервер, ккоторому уже применена конфигурация, описанная вроли.


Упростите процесс предварительной настройки серверов


Почему так важно иметь простой способ получить чистую конфигурацию? Длятого, чтобы уменьшить влияние Configuration Drift, который современем будет неизбежно накапливаться. Configuration Drift это неконсистентность конфигурации машины, описанной вкоде, поотношению кеё фактическому состоянию. Его источники это ручные изменения намашинах, тестирование гипотез, ресурсы, которые приизменении вышли из-подуправления Puppet.


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


В идеале нужно иметь возможность получить чистое состояние, отправив машину впереналивку простым API-вызовом. Мы делаем это через netboxAPI, который расширили подсвои нужды. Подкапотом там загрузка поPXE и netboot-образ Debian, шаблонизация preseed'ов наоснове параметров, переданных вAPI, много низкоуровневой настройки и взаимодействия поIPMI черезRedfish API. И, конечно же, болей, связанных сразной его реализацией уразных вендоров.


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


Настройте инструменты тестирования инфраструктурного кода


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


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


Когда мы перешли с3.7 на6 версию Puppet, то поняли, что появилась куча крутых инструментов длятестирования. Последовательность тестирования инфраструктурного кода выглядит так:


  1. Запуск линтера.
  2. Юнит-тесты.
  3. Приёмочные тесты

Наэтих трёх шагах мы делаем следующее:


  1. Проверяем валидность синтаксиса, соответствие стайлгайдам и т.п.
  2. Проверяем, что код компилируется вкаталог, отлавливаем ошибки duplicate resource declaration. Вэтих тестах можем зафиксировать определённый контракт: например, код должен содержать ресурс сервис, который должен рестартовать приизменениях вопределённых файлах.
  3. На стадии приёмочных тестов применяем код вDocker-контейнере, проверяем, что сервис работает припомощи inspec.

Приёмочное тестирование длямодуля Kubernetes

Кластеры Kubernetes мы разворачиваем припомощи Puppet и делаем это встиле "Kubernetes The Hard Way", то есть контролируем настройку компонентов кластера досамых мелочей.


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


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


Код тестов, которые выполняют эту проверку, выглядят так:


  context 'application deployment' do    it 'can deploy an application into a namespace and expose it' do      shell('systemctl restart kubelet')      shell('count=0;        while [[ $(kubectl get pods -n tiller -l name=tiller -o \'jsonpath={..status.conditions[?(@.type=="Ready")].status}\') != "True" ]];          do            if [[ count -gt 180 ]]; then              break;            fi;            sleep 1 && ((count++));          done')      shell('kubectl create -f /tmp/nginx.yaml', acceptable_exit_codes: [0]) do |r|        expect(r.stdout).to match(%r{namespace/nginx created\nconfigmap/my-nginx-config created\ndeployment.apps/my-nginx created\nservice/my-nginx created\n})      end    end    it 'can access the deployed service' do      shell('count=0;        while [[ $(kubectl get pods -n nginx -l run=my-nginx -o \'jsonpath={..status.conditions[?(@.type=="Ready")].status}\') != "True" ]];          do            if [[ count -gt 180 ]]; then              break;            fi;            sleep 1 && ((count++));          done')      shell('curl --connect-timeout 1 --retry-delay 1 --retry-max-time 300 --retry 150 -s --retry-connrefused 10.100.10.5', acceptable_exit_codes: [0]) do |r|        expect(r.stdout).to match %r{Welcome to nginx!}      end    end end

Если все шаги прошли безошибок, тест считается успешным. Приёмочные тесты мы запускаем наCI накаждое изменение.


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


Вот список инструментов, которые помогут помочь настроить тестирование инфракода:



И неплохая статья про юнит-тестирование:



Development kit для инфраструктурного кода


Если хотите, чтобы разработчики инфракода использовали CI/CD или проверяли свой код допуша врепу снабдите их инструментом, который поумолчанию поддерживает необходимый workflow.


В паппет-экосистеме есть отличный инструмент PDK, который активно используется всообществе. Но его мы использовать не стали, потому что он был несовместим снашим инструментарием, и пришлось бы многое дорабатывать. ВPDK впервую очередь не хватило возможности работать сcontrol repo и тестирования сиспользованием Kitchen и Docker. Длятестирования PDK использует Beaker, укоторого довольно высокий порог входа.


Поэтому мы написали свой инструмент, который позволяет:


  • Создать изшаблона пустой проект, готовый кработе: тесты, CI пайплайны и прочее.
  • Сгенерировать заготовки дляманифестов, тестов, паппет-функций.
  • Запускать статические валидаторы кода, юнит-тесты, приёмочные тесты.
  • Разрешить зависимости вcontrol repo, показать, есть ли более новые версии зависимостей.
  • Сгенерировать документацию вмаркдауне издокстрингов.
  • Собрать модуль и запушить вовнутренний репозиторий.


Когда разработчик инфракода создаёт новый модуль припомощи development tool, он сразу получает репозиторий снастроенными сборками наCI длястатического анализа, запуска тестов и релиза модуля.


После бутстрапа проекта врепозитории уже будет настроен инструментарий дляработы скодом (puppet-rspec, puppet-linter, test-kitchen) и настроены гит хуки, которые запускают нужный инструмент накоммит или пуш. Всозданном репозитории поумолчанию применяются политики, запрещающие пуш вмастер и мердж ветки, если тесты упали или код не прошел ревью.


IDE для Puppet

Кстати, вкачестве IDE дляразработки паппет-кода неплохо подходит VSCode, внём есть замечательный плагин схорошей поддержкой DSL, автодополнением и сниппетами.


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


Об управлении зависимостями в инфраструктурном коде


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


В управлении зависимостями вPuppet есть много странных и неочевидных вещей. Например, зависимости вмодулях можно указывать двумя разными способами: metadata.json и Puppetfile. Они немного отличаются посвоим возможностям, и разные инструменты по-разному их обрабатывают. Официально поддерживаемого инструмента поразрешению зависимостей нет. Есть librarian-puppet, который, вотличие отофициального r10k, умеет резолвить зависимости второго и высших порядков. Но проект давно не развивается и не имеет нормальной документации, хотя задачу свою вцелом выполняет. За неимением лучшего инструмента взяли его он применяется везде, где требуется резолв зависимостей: вacceptance-тестах и придеплое кода напаппет-сервер.


Достаточно долго мы искали подходящий путь. Сначала подключали модули как гит репу, а версионировали git-тегами, вот так:


mod 'dba-clickhouse',  :git => 'ssh://git@github.com/iac/dba-clickhouse.git',  :ref => '1.2.2'mod 'dba-kafka',  :git => 'ssh://git@github.com/iac/dba-kafka.git',  :ref => '1.2.0'

Такой способ работает, но требует явно указывать версию модуля, и не даёт завязаться намажорную или минорную версию. Дляболее гибкого версионирования придётся поднять собственный локальный Puppet Forge, загружать модули внего, а зависимости резолвить черезlibrarian-puppet.


Модули мы версионируем поsemver, по отношению ктому, какой интерфейс предоставляют публичные классы внутри модуля. То есть если интерфейс изменился обратно несовместимо, поднимается мажорная версия, впротивном случае минорная:


# Puppetfilemod 'arch-puppetserver', '0.20.5' # подключаем строго указанную версию модуляmod 'arch-vault', '~> 2.1' # подключаем модуль в пределах мажорной версииmod 'si-lxc' # используем самую последниюю версию

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


[22:39:43] in dba-control on  production via  ruby-2.5.1 at   unstable $ iack dep show[] Collecting modules metadataFULL NAME            | CURRENT VERSION | LATEST VERSION | OUT OF DATE?  ---------------------|-----------------|----------------|---------------si-lxc               | latest          | 0.3.2          | N/A           si-base              | latest          | 1.3.1          | N/A           petems-hiera_vault   | v0.4.1          |                | Majorarch-vault           | 2.1.0           | 2.1.0          | No   dba-postgresql       | 0.1.2           | 0.1.3          | Tiny dba-pgbouncer        | 0.4.0           | 0.5.1          | Minorsi-grub              | 0.1.0           | 0.1.0          | No   si-collectd          | 0.2.3           | 0.2.4          | Tiny si-confluent         | 0.3.0           | 0.3.0          | No   dba-redis            | 0.2.3           | 0.2.3          | No   dba-collectd_plugins | latest          | 0.2.0          | N/A           dba-mongodb          | 0.2.1           | 0.2.1          | No   dba-patroni          | 0.1.4           | 0.2.4          | Minordba-cruise_control   | 0.1.1           | 0.1.2          | Tiny dba-lxd              | 0.7.0           | 0.7.0          | No   dba-clickhouse       | 1.2.1           | 1.2.2          | Tiny dba-zookeeper        | 2.0.0           | 2.0.0          | No   si-td_agent          | 0.1.0           | 0.1.0          | No   dba-kafka            | 1.1.6           | 1.2.1          | Minorarch-puppetserver    | 0.20.1          | 0.20.2         | Tiny pcfens-filebeat      | 4.1.0           | 4.4.1          | MinorKyleAnderson-consul  | 5.0.3           | 6.0.1          | Majorpuppetlabs-apt       | 6.3.0           | 7.4.2          | Majorpuppetlabs-stdlib    | 5.2.0           | 6.3.0          | Major

Вот несколько полезных ссылок потеме:



О важности code style и документации дляинфраструктурного кода


Почему так важно иметь code style вразработке инфраструктурного кода? Всё как и слюбым другим кодом инфраструктурный код пишется один раз, а читается потом десятками людей напротяжении лет. Поэтому нужен некий стандарт, описывающий лучшие практики, который облегчит чтение кода и его поддержку, адаптацию новых инженеров. Он также упрощает и процесс review кода проще урегулировать спорные моменты, кинув ссылкой наподходящий пункт издокумента.


В Puppet сэтим всё отлично. The puppet language style guide содержит все основные рекомендации понаписанию кода. Puppet-lint, который мы запускаем наCI, проверяет соблюдение этих рекомендаций и позволяет добавлять внего собственные проверки.


Внутри Авито мы его немного расширили и дополнили его своими, более высокоуровневыми правилами и рекомендациями. Их мы выложили вместе с шаблонами модулей и control repo:



Поскольку мы используем свой development kit, важно облегчить процесс онбординга новых инженеров и адаптации старых:


  • иметь единую точку входа вовнутреннюю документацию дляинженера инфраструктуры;
  • описать процесс работы отпростого к сложному: отhow to поразработке простейшего модуля доболее справочных материалов. Часть этой документации была переработана и превратилась встатью наХабре;
  • предоставить канал поддержки, где можно задать любой вопрос потеме.

Удобное управление секретами это важно


Управление секретами дляинфракода должно быть удобным и простым, иначе секреты начинают коммитить вкод. ВPuppet управление секретами удобно делать черезинтеграцию Hiera и Vault. На Гитхабе есть hiera-backend, который позволяет получать их значения прямо изvault черезhiera_lookup.


Для работы ссекретами вАвито есть модуль-обёртка, который позволяет либо получить секрет впеременную, либо положить файл-секрет вопределённое место всистеме. Первый способ работает через функцию, которая вызывается вкоде вот так:


$token_data = vault::secret_field('tokens.csv', 'data')

В этом примере впеременную token_data получаем значение поля 'data' изсекрета tokens.csv, который находится вVault. Всамом Vault секреты хранятся иерархически, также, как вHiera:


$ vault-util ls puppet/arch/      common/nodes/roles/

Таким образом, если мы хотим иметь общее значение секрета длявсех машин, достаточно положить его вcommon. Если оно разное длякаждой роли или ноды вroles/ или nodes/.

Второй способ это дефайн и специальный формат секрета вволте, который содержит различные метаданные файла-секрета, такие как имя файла, владелец, права нафайл. Такой способ мы используем дляхранения TLS-сертификатов и ключей.


Для тех, кто хочет подробнее разобраться втом, как всё это работает, мы выложили модуль дляуправления секретами наГитхаб. Внём также можно посмотреть примеры того, как тестировать манифесты и функции наPuppet:



Canary релизы инфраструктурного кода


В Puppet есть интересный механизм, который позволяет выкатить код изветки control repo. Все ветки репозитория control repo отображаются наокружении, а каждая нода принадлежит кодному из них. Информация обэтом отдаётся изENC вместе сименем роли.


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


Это ещё один, финальный, способ протестировать свои изменения, и не уронить систему.


О достоинствах и недостатках Puppet


Если говорить одостоинствах Puppet, я бы назвал отличную документацию, развитый тулинг вокруг, очень большую гибкость и расширяемость инструмента. Если не хватает возможностей DSL его можно расширять наRuby. Hiera отличное решение дляхранения параметров, которые передаются вроли. Можно обеспечить максимальную стандартизацию инфраструктуры, приэтом сохранить возможность внести изменения сгранулярностью доконкретной машины. Данные вHiera можно выносить вразличные бэкенды, а если не хватает подходящего, можно написать свой.


Самый большой недостаток Puppet это, пожалуй, высокий порог входа и огромное количество способов решить одну и ту же задачу. Это обратная сторона гибкости. Даже спустя годы работы сэтим инструментом иногда всё равно непонятно, как лучше организовать код: как использовать профили, какие параметры выносить вHiera, а какие оставлять вкоде. Мы смогли выработать какие-то правила, но это достаточно специфичная тема, поэтому её оставим зарамками статьи.


Puppet наследовал у Ruby подход, когда узадачи имеется несколько решений. Это может быть интересно, если ты водиночку пилишь небольшой pet project. Но если ты работаешь синфраструктурой, где крайне важна стабильность и простота, вкоманде изнескольких десятков инженеров это очень вредит. Обычно получается так: если инструмент позволяет решать одну задачу несколькими способами, то будет выбран самый простой и, скорее всего, неправильный.


Ещё один недостаток плохая обратная связь привнесении изменений. Он впринципе присущ всем инструментам, работающим поpull-модели. Неизвестно, вкакой момент времени применятся изменения, которые попали вмастер. Длянекоторых задач это становится критичным, и приходится изобретать велосипеды, чтобы pull превратить вpush. Bolt, который Puppetlabs предлагает дляподобных задач, выглядит странно, сложно интегрируется сPuppetDB, и отего использования мы пока отказались.


Суммируя


Чтобы повысить эффективность и прозрачность работы синфраструктурой и получить качественный код, который будет просто переиспользовать, мы:


  1. Вместо безупречного инструмента концентрируемся наулучшении тулинга и практик, которые применяем приразработке.
  2. Определяем границы применимости каждого инструмента и фиксируем их.
  3. Стараемся уменьшать связанность инфраструктурного кода и более контролируемое применение изменений засчёт версионирования его частей.
  4. Тестируем код и обеспечиваем быструю обратную связь привнесении изменений.
  5. Обеспечиваем запуск тестов наCI и вывод их результатов приревью кода.
  6. Используем пайплайны и инструменты, которые поддерживают необходимый workflow дляинфраструктурного кода.
  7. Используем External Node Classifier вместо регулярок.
  8. Упрощаем процессы предварительной настройки серверов.
  9. Обеспечиваем безопасное и удобное получение секретов винфраструктуру.
Подробнее..

Перевод Как спокойно спать, когда у вас облачный сервис основные архитектурные советы

19.08.2020 18:13:30 | Автор: admin
LOST by sophiagworld

В этой статей собраны некоторые общие шаблоны, помогающие инженерам работать с масштабными сервисами, к которым делают запросы миллионы пользователей.

По опыту автора, это не исчерпывающий список, но действительно эффективные советы. Итак, начнем.

Переведено при поддержке Mail.ru Cloud Solutions.

Начальный уровень


Перечисленные ниже меры относительно просты в реализации, но дают высокую отдачу. Если вы раньше их не предпринимали, то будете удивлены значительными улучшениями.

Инфраструктура как код


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

Развертывание 100 виртуальных машин

  • с Ubuntu
  • 2 ГБ RAM на каждой
  • у них будет следующий код
  • с такими параметрами

Вы можете отслеживать изменения в инфраструктуре и быстро возвращаться к ним с помощью системы управления версиями.

Модернист во мне говорит, что можно использовать Kubernetes/Docker, чтобы сделать всё выше перечисленное, и он прав.

Кроме того, обеспечить автоматизацию, можно с помощью Chef, Puppet или Terraform.

Непрерывная интеграция и доставка


Для создания масштабируемого сервиса важно наличие конвейера сборки и теста для каждого пул-реквеста. Даже если тест самый простой, он, по крайней мере, гарантирует, что код, который вы деплоите, компилируется.

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


Нет ничего прекраснее, чем видеть эти галочки

Для этой технологии можете оценить Github, CircleCI или Jenkins.

Балансировщики нагрузки


Итак, мы хотим запустить балансировщик нагрузки, чтобы перенаправлять трафик, и обеспечить равную нагрузку на всех узлах или работу сервиса в случае сбоя:


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

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

RayID, сorrelation ID или UUID для запросов


Вам когда-нибудь встречалась ошибка в приложении с сообщением вроде такого: Что-то пошло не так. Сохраните этот id и отправьте его в нашу службу поддержки?


Уникальный идентификатор, correlation ID, RayID или любой из вариантов это уникальный идентификатор, который позволяет отслеживать запрос в течение его жизненного цикла. Это позволяет отследить весь путь запроса в логах.


Пользователь делает запрос к системе A, затем А связывается с B, та связывается с C, сохраняет в X и затем запрос возвращается в A

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

Средний уровень


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

Централизованное ведение журналов


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

Хотя это звучит как забавное приключение, однако, лучше убедиться, что у вас есть возможность поиска по всем журналам из одного места. Я решил задачу централизации журналов с помощью встроенной функциональности стека ELK: здесь поддерживается сбор журналов с возможностью поиска. Это действительно поможет решить проблему с поиском конкретного журнала. В качестве бонуса вы можете создавать диаграммы и тому подобные забавные штуки.


Функциональность стека ELK

Агенты мониторинга


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

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

Для небольших и средних проектов я рекомендую Postman для мониторинга и документирования API. Но в целом просто следует убедиться, что у вас есть способ узнать, когда произошел сбой, и получить своевременное оповещение.

Автомасштабирование в зависимости от нагрузки


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


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

Система экспериментов


Хорошим способом безопасно развернуть обновления станет возможность протестировать что-то для 1% пользователей в течение часа. Вы, конечно, видели такие механизмы в действии. Например, Facebook показывает части аудитории другой цвет или меняет размер шрифта, чтобы посмотреть, как пользователи воспринимают изменения. Это называют A/B-тестированием.

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

Продвинутый уровень


Здесь советы, которые довольно сложно реализовать. Вероятно, вам потребуется немного больше ресурсов, поэтому небольшой или средней компании будет трудно с этим справиться.

Сине-зеленые развертывания


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

Этот шаг зависит от наличия балансировщика нагрузки. Представим, что у вас версия N вашего программного обеспечения, а затем вы хотите развернуть версию N+1.

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

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

  • тот, который есть прямо сейчас (N);
  • следующая версия (N+1).

Вы указываете балансировщику нагрузки перенаправить процент трафика на новую версию (N+1), в то время как сами активно отслеживаете регрессии.


Здесь у нас есть зеленый деплой N, который нормально работает. Мы пытаемся перейти к следующей версии этого деплоя

Сначала мы посылаем действительно небольшой тест, чтобы посмотреть, работает ли наш деплой N+1 с небольшим количеством трафика:


Наконец, у нас есть набор автоматических проверок, которые мы в конечном итоге запускаем до тех пор, пока наше развертывание не будет завершено. Если вы очень-очень осторожны, также можете сохранить свое развертывание N навсегда для быстрого отката в случае плохой регрессии:


Если хотите перейти на еще более продвинутый уровень, пусть всё в сине-зеленом деплое выполняется автоматически.

Обнаружение аномалий и автоматическое смягчение последствий


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


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

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

Вот и всё!


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

Автор оригинальной статьи приглашает читателей оставлять свои комментарии и вносить изменения. Статья распространяется как open source, пул-реквесты автор принимает на Github.

Что еще почитать по теме:

  1. Go и кэши CPU.
  2. Kubernetes в духе пиратства с шаблоном по внедрению.
  3. Наш канал Вокруг Kubernetes в Телеграме.
Подробнее..

Обновление процесса CICD год спустя

05.04.2021 02:07:14 | Автор: admin

Это четвертая и заключительная часть цикла об обновлении CI/CD процессов. Кстати, вот оглавление:
Часть 1: что есть, почему оно не нравится, планирование, немного bash. Я бы назвал эту часть околотехнической.
Часть 2: teamcity.
Часть 3: octopus deploy.
Часть 4: внезапно вполне себе техническая. Что произошло за прошедший год.

Сейчас у нас есть рабочая система доставки обновлений, которая прошла испытание временем. О настройке этой системы можно прочесть в первых трёх частях, а сейчас предлагаю вкратце вспомнить что там было.

Осуществлялся переезд CI/CD системы с CruiseControl.NET + git deploy на Teamcity + octopus. Будем честны, CD там и не пахло. Об этом, возможно, будет отдельная статья, но не в этом цикле.
С момента выхода первой статьи цикла прошло чуть больше года, с момента начала работы системы в проде - примерно полтора. Процесс разработки во время внедрения новой системы практически не прерывался. Было два раза, когда делали code freeze: один раз в момент перехода с mercurial репозитория в git (чтобы не потерять коммиты во время конвертации), и второй раз во время перехода билда production окружения с ccnet на teamcity (просто так, на всякий случай).
В результате мы получили систему которая способна наиболее оптимально (с минимальными время- и ресурсозатратами, а также с минимальными рисками) доставлять обновления во все существующие окружения.

С момента выхода 3 части статьи в конфигурации произошли некоторые изменения, о которых, наверное, стоит рассказать.

Что произошло за этот год

  1. Мы практически полностью отказались от конфигураций вида Build + deploy. Теперь используем отдельно Build и отдельно Deploy. Последние всё также вызываются из teamcity, но это сделано исключительно для упрощения жизни всем менее причастным. На самом деле, для того чтобы обезопасить Octopus от вмешательства любопытных.

  2. Полностью перешли на semver. К сожалению, до момента внедрения девопс в проект, ни о каком semver речи не было. Картинка с этой версионностью уже мелькала в 3 части, останавливаться подробно не будем.

  3. Появился опыт настройки деплоя на сервере без каких-либо доступов, только с установленным octopus агентом. Не то, чтобы его не было, просто он был забыт как страшный сон за много лет. А тут пришлось вспоминать. Приятного мало, но на удивление, терпимо.

  4. Перешли с Visual studio (sln) раннера на .net msbuild ввиду окончания поддержки первого (Teamcity).

  5. Для Special Module (см часть 1) появился интересный вызов билда из деплоя с пробросом параметров через reverse.dep

  6. Появился какой-никакой роллбек.

  7. Переработали variable setы в octopus, используем tenant variables.

  8. Практически везде перешли от хранения connection string в репозитории на хранение в Octopus и подстановкой при деплое. К сожалению, раньше хранили именно в репозитории.

  9. Для деплоя особо важных модов добавили защиту от тестировщика (подробнее чуть позже).

  10. Выросли на 7 новых тенантов (клиентов).

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

Build-chain наоборот (пункт 4)

Для Special module, как и для любых других есть несколько окружений. Список всех пайплайнов для этого модуля в teamcity выглядит так:

Build конфигурация используется одна, с вот таким параметром ветки:

Также в данной конфигурации используются две prompted переменные типа Select: env.Environment и env.buildBranch. Выглядят они примерно одинаково, отличаются только Items. Для каждого env ставится в соответствие ветка репозитория.

С учётом всех настроек, перечисленных выше, запуск билда вручную выглядит следующим образом:

В каждой Deploy конфигурации, есть зависимость от актуальности конфигурации build и параметры типа reverse.dep, которые при запуске Build устанавливают для него env.Environment и env.buildBranch. Например, для development это выглядит так:

Как всё это работает вместе: при нажатии кнопки deploy соответствующего окружения проверяется наличие изменений в репозитории. Если изменения есть - запускается конфигурация Build с установленными через reverse.dep переменными. По завершению билда, запускается ожидавший всё это время деплой новой версии пакета.

Rollback (пункт 6)

Rollback построен на следующем алгоритме:

  1. Определить номер текущего и предыдущего релизов в octopus для Core и Module.

  2. Откатить Core (задеплоить предыдущий релиз)

  3. Откатить Module.

Octopus хранит 3 предыдущих релиза так, на всякий случай. Rollback из teamcity работает только с предыдущим релизом. Откат на более давний релиз надо делать вручную, но такой необходимости ни разу не возникало. Так выглядят определение версий:

$packageRelease = ((%env.octoExe% list-deployments --server="%env.octoUrl%" --apikey="%env.octoApiKey%" --project="ProjectName.%env.modName%" --environment="%env.Environment%" --outputFormat=json) | ConvertFrom-Json).Version[0..1]$coreRelease = (((%env.octoExe% list-deployments --server="%env.octoUrl%" --apikey="%env.octoApiKey%" --project="%env.coreProjectName%" --environment="%env.Environment%" --outputFormat=json) | ConvertFrom-Json).Version | Get-Unique)[0..1]$OctopusPackageCurrentRelease = $packageRelease[0]$OctopusPackagePreviousRelease = $packageRelease[1]$corePreviousVersion = $OctopusPackagePreviousRelease | %{ $_.Split('-')[0]; }$coreEnv = $OctopusPackagePreviousRelease | %{ $_.Split('-')[1]; } |  %{ $_.Split('+')[0]; }$OctopusCoreCurrentRelease = $coreRelease[0]$OctopusCorePreviousRelease = "$corePreviousVersion-$coreEnv"Write-Host "##teamcity[setParameter name='OctopusPackageCurrentRelease' value='$OctopusPackageCurrentRelease']"Write-Host "##teamcity[setParameter name='OctopusPackagePreviousRelease' value='$OctopusPackagePreviousRelease']"Write-Host "##teamcity[setParameter name='OctopusCoreCurrentRelease' value='$OctopusCoreCurrentRelease']"Write-Host "##teamcity[setParameter name='OctopusCorePreviousRelease' value='$OctopusCorePreviousRelease']"

Откат является деплоем соответствующей версии, поэтому глобально ничем не отличается от шага Deploy.2 описанного в части 2. Меняется только Release Number. Вместо latest используется %OctopusCorePreviousRelease% и %OctopusPackagePreviousRelease% соответственно.

Переработка variable sets

Раньше все переменные тенантов хранились в конфигурациях проектов и разруливались расстановкой скоупов. Вот хороший пример из части 3:

При количестве тенантов больше 3 это оказывается неудобно. Поэтому, перешли к хранению переменных клиентов в предназначенном для этого месте - tenant variables - common variables.
Так списки переменных проектов стали чище, и там больше нет каши.

Защита от тестировщика (пункт 9)

В список задач тестировщика входит также деплой на некоторые окружения. Туда, куда деплои не попадают автоматически из за ограничений. Зачастую это выглядит как клик клик клик клик по кнопкам Run не задумываясь. Исключение составляет prod окружение, но это не точно. Пару раз были прецеденты деплоя модов, которые помечены как secure. Это особая категория модов, которыми пользуются особые люди. Они очень любят стабильность и все релизы у них планируются, а набор новых фич обсуждается. В общем, для этих модов пришлось добавить элементарную защиту в виде всплывающего Are you sure и требованием ввести ответ буквами.

Реализовано это с помощью prompted переменной и regexp.

Заключение

В данный момент я работаю над этим проектом по минимуму. Саппорт практически не требуется, всё работает практически без моего участия. Где-то есть continuous deployment, где-то пришлось ограничиться delivery. Там где надо нажимать кнопки вручную - справляются тестировщик и главный девелопер. Время добавления новых конфигураций (по факту нового клиента) вместе с проверкой работоспособности - час с чайком и без напряга. С CCNet такой результат показался бы фантастикой при условии отcутствия дичайшего оверхеда со стороны ресурсов сервера. Да и удобства никакого. Пропала проблема бесконечной нехватки места, так как на сервере не хранятся лишние копии одного и того же. И даже rollback показал себя с хорошей стороны, и на удивление работает.Всё работает классно шустро, и самое главное - стабильно и прогнозируемо.

Бросать проект в мои планы не входит, но и какие-то крупные изменения в дальнейшем пока не планируются. Так что, я изредка поглядываю в Octopus, радуюсь тому что все работает без моего участия и пилю новые проекты.

Статья получилось вполне технической. На описание неприятных моментов и места то не осталось. Могу сказать, что все неприятные моменты связаны исключительно с впечатлением от windows, а не с проектом. Это всё таки был мой первый проект на оконном стеке. Впечатления непосредственно от проекта только самые лучшие. Хоть это и древнее легаси-зло, проект на самом деле очень крутой и интересный. И опыт поддержки и постановки таких проектов на новые рельсы без преувеличения можно назвать бесценным. В общем, в мире стало на один хороший проект с devops методологией больше.

Подробнее..

PVS-Studio Анализ pull request-ов в Azure DevOps при помощи self-hosted агентов

27.07.2020 18:22:43 | Автор: admin


Статический анализ кода показывает наибольшую эффективность во время внесения изменений в проект, поскольку ошибки всегда сложнее исправлять в будущем, чем не допустить их появления на ранних этапах. Мы продолжаем расширять варианты использования PVS-Studio в системах непрерывной разработки и покажем, как настроить анализ pull request-ов при помощи self-hosted агентов в Microsoft Azure DevOps, на примере игры Minetest.

Вкратце о том, с чем мы имеем дело


Minetest это открытый кроссплатформенный игровой движок, содержащий около 200 тысяч строк кода на C, C++ и Lua. Он позволяет создавать разные игровые режимы в воксельном пространстве. Поддерживает мультиплеер, и множество модов от сообщества. Репозиторий проекта размещен здесь: https://github.com/minetest/minetest.

Для настройки регулярного поиска ошибок использованы следующие инструменты:

PVS-Studio статический анализатор кода на языках C, C++, C# и Java для поиска ошибок и дефектов безопасности.

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

Для выполнения задач разработки в Azure возможно использование виртуальных машин-агентов Windows и Linux. Однако запуск агентов на локальном оборудовании имеет несколько весомых преимуществ:

  • У локального хоста может быть больше ресурсов, чем у ВМ Azure;
  • Агент не "исчезает" после выполнения своей задачи;
  • Возможность прямой настройки окружения, и более гибкое управление процессами сборки;
  • Локальное хранение промежуточных файлов положительно влияет на скорость сборки;
  • Можно бесплатно выполнять более 30 задач в месяц.

Подготовка к использованию self-hosted агента


Процесс начала работы в Azure подробно описан в статье "PVS-Studio идёт в облака: Azure DevOps", поэтому перейду сразу к созданию self-hosted агента.

Для того, чтобы агенты имели право подключиться к пулам проекта, им нужен специальный Access Token. Получить его можно на странице "Personal Access Tokens", в меню "User settings".

image2.png

После нажатия на "New token" необходимо указать имя и выбрать Read & manage Agent Pools (может понадобиться развернуть полный список через "Show all scopes").

image3.png

Нужно скопировать токен, так как Azure больше его не покажет, и придется делать новый.

image4.png

В качестве агента будет использован Docker контейнер на основе Windows Server Core. Хостом является мой рабочий компьютер на Windows 10 x64 с Hyper-V.

Сначала понадобится расширить объём дискового пространства, доступный Docker контейнерам.

В Windows для этого нужно модифицировать файл 'C:\ProgramData\Docker\config\daemon.json' следующим образом:

{  "registry-mirrors": [],  "insecure-registries": [],  "debug": true,  "experimental": false,  "data-root": "d:\\docker",  "storage-opts": [ "size=40G" ]}

Для создания Docker образа для агентов со сборочной системой и всем необходимым в директории 'D:\docker-agent' добавим Docker файл с таким содержимым:

# escape=`FROM mcr.microsoft.com/dotnet/framework/runtimeSHELL ["cmd", "/S", "/C"]ADD https://aka.ms/vs/16/release/vs_buildtools.exe C:\vs_buildtools.exeRUN C:\vs_buildtools.exe --quiet --wait --norestart --nocache `  --installPath C:\BuildTools `  --add Microsoft.VisualStudio.Workload.VCTools `  --includeRecommendedRUN powershell.exe -Command `  Set-ExecutionPolicy Bypass -Scope Process -Force; `  [System.Net.ServicePointManager]::SecurityProtocol =    [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; `  iex ((New-Object System.Net.WebClient)    .DownloadString('https://chocolatey.org/install.ps1')); `  choco feature enable -n=useRememberedArgumentsForUpgrades;  RUN powershell.exe -Command `  choco install -y cmake --installargs '"ADD_CMAKE_TO_PATH=System"'; `  choco install -y git --params '"/GitOnlyOnPath /NoShellIntegration"'RUN powershell.exe -Command `  git clone https://github.com/microsoft/vcpkg.git; `  .\vcpkg\bootstrap-vcpkg -disableMetrics; `  $env:Path += '";C:\vcpkg"'; `  [Environment]::SetEnvironmentVariable(    '"Path"', $env:Path, [System.EnvironmentVariableTarget]::Machine); `  [Environment]::SetEnvironmentVariable(    '"VCPKG_DEFAULT_TRIPLET"', '"x64-windows"',  [System.EnvironmentVariableTarget]::Machine)RUN powershell.exe -Command `  choco install -y pvs-studio; `  $env:Path += '";C:\Program Files (x86)\PVS-Studio"'; `  [Environment]::SetEnvironmentVariable(    '"Path"', $env:Path, [System.EnvironmentVariableTarget]::Machine)RUN powershell.exe -Command `  $latest_agent =    Invoke-RestMethod -Uri "https://api.github.com/repos/Microsoft/                          azure-pipelines-agent/releases/latest"; `  $latest_agent_version =    $latest_agent.name.Substring(1, $latest_agent.tag_name.Length-1); `  $latest_agent_url =    '"https://vstsagentpackage.azureedge.net/agent/"' + $latest_agent_version +  '"/vsts-agent-win-x64-"' + $latest_agent_version + '".zip"'; `  Invoke-WebRequest -Uri $latest_agent_url -Method Get -OutFile ./agent.zip; `  Expand-Archive -Path ./agent.zip -DestinationPath ./agentUSER ContainerAdministratorRUN reg add hklm\system\currentcontrolset\services\cexecsvc        /v ProcessShutdownTimeoutSeconds /t REG_DWORD /d 60  RUN reg add hklm\system\currentcontrolset\control        /v WaitToKillServiceTimeout /t REG_SZ /d 60000 /fADD .\entrypoint.ps1 C:\entrypoint.ps1SHELL ["powershell", "-Command",       "$ErrorActionPreference = 'Stop';     $ProgressPreference = 'SilentlyContinue';"]ENTRYPOINT .\entrypoint.ps1

В результате получится сборочная система на основе MSBuild для C++, с Chocolatey для установки PVS-Studio, CMake и Git. Для удобного управления библиотеками, от которых зависит проект, собирается Vcpkg. А также скачивается свежая версия, собственно, Azure Pipelines Agent.

Для инициализации агента из ENTRYPOINT-а Docker файла вызывается PowerShell скрипт 'entrypoint.ps1', в который нужно добавить URL "организации" проекта, токен пула агентов, и параметры лицензии PVS-Studio:

$organization_url = "https://dev.azure.com/<аккаунт Microsoft Azure>"$agents_token = "<token агента>"$pvs_studio_user = "<имя пользователя PVS-Studio>"$pvs_studio_key = "<ключ PVS-Studio>"try{  C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat  PVS-Studio_Cmd credentials -u $pvs_studio_user -n $pvs_studio_key    .\agent\config.cmd --unattended `    --url $organization_url `    --auth PAT `    --token $agents_token `    --replace;  .\agent\run.cmd} finally{  # Agent graceful shutdown  # https://github.com/moby/moby/issues/25982    .\agent\config.cmd remove --unattended `    --auth PAT `    --token $agents_token}

Команды для сборки образа и запуска агента:

docker build -t azure-agent -m 4GB .docker run -id --name my-agent -m 4GB --cpu-count 4 azure-agent

image5.png

Агент запущен и готов выполнять задачи.

image6.png

Запуск анализа на self-hosted агенте


Для анализа PR создается новый pipeline со следующим скриптом:

image7.png

trigger: nonepr:  branches:    include:    - '*'pool: Defaultsteps:- script: git diff --name-only    origin/%SYSTEM_PULLREQUEST_TARGETBRANCH% >    diff-files.txt  displayName: 'Get committed files'- script: |    cd C:\vcpkg    git pull --rebase origin    CMD /C ".\bootstrap-vcpkg -disableMetrics"    vcpkg install ^    irrlicht zlib curl[winssl] openal-soft libvorbis ^    libogg sqlite3 freetype luajit    vcpkg upgrade --no-dry-run  displayName: 'Manage dependencies (Vcpkg)'- task: CMake@1  inputs:    cmakeArgs: -A x64      -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake      -DCMAKE_BUILD_TYPE=Release -DENABLE_GETTEXT=0 -DENABLE_CURSES=0 ..  displayName: 'Run CMake'- task: MSBuild@1  inputs:    solution: '**/*.sln'    msbuildArchitecture: 'x64'    platform: 'x64'    configuration: 'Release'    maximumCpuCount: true  displayName: 'Build'- script: |    IF EXIST .\PVSTestResults RMDIR /Q/S .\PVSTestResults    md .\PVSTestResults    PVS-Studio_Cmd ^    -t .\build\minetest.sln ^    -S minetest ^    -o .\PVSTestResults\minetest.plog ^    -c Release ^    -p x64 ^    -f diff-files.txt ^    -D C:\caches    PlogConverter ^    -t FullHtml ^    -o .\PVSTestResults\ ^    -a GA:1,2,3;64:1,2,3;OP:1,2,3 ^    .\PVSTestResults\minetest.plog    IF NOT EXIST "$(Build.ArtifactStagingDirectory)" ^    MKDIR "$(Build.ArtifactStagingDirectory)"    powershell -Command ^    "Compress-Archive -Force ^    '.\PVSTestResults\fullhtml' ^    '$(Build.ArtifactStagingDirectory)\fullhtml.zip'"  displayName: 'PVS-Studio analyze'  continueOnError: true- task: PublishBuildArtifacts@1  inputs:    PathtoPublish: '$(Build.ArtifactStagingDirectory)'    ArtifactName: 'psv-studio-analisys'    publishLocation: 'Container'  displayName: 'Publish analysis report'

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

image8.png


image9.png

В скрипте происходит сохранение списка измененных файлов, полученного при помощи git diff. Затем обновляются зависимости, генерируется solution проекта через CMake, и производится его сборка.

Если сборка прошла успешно, запускается анализ изменившихся файлов (флаг '-f diff-files.txt'), игнорируя созданные CMake вспомогательные проекты (выбираем только нужный проект флагом '-S minetest'). Для ускорения поиска связей между заголовочными и исходными C++ файлами создается специальный кэш, который будет храниться в отдельной директории (флаг '-D C:\caches').

Таким образом, мы теперь можем получать отчеты об анализе изменений в проекте.

image10.png


image11.png

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

image13.png

Некоторые ошибки, найденные в Minetest


Затирание результата

V519 The 'color_name' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 621, 627. string.cpp 627

static bool parseNamedColorString(const std::string &value,                                  video::SColor &color){  std::string color_name;  std::string alpha_string;  size_t alpha_pos = value.find('#');  if (alpha_pos != std::string::npos) {    color_name = value.substr(0, alpha_pos);    alpha_string = value.substr(alpha_pos + 1);  } else {    color_name = value;  }  color_name = lowercase(value); // <=  std::map<const std::string, unsigned>::const_iterator it;  it = named_colors.colors.find(color_name);  if (it == named_colors.colors.end())    return false;  ....}

Эта функция должна производить разбор названия цвета с параметром прозрачности (например, Green#77) и вернуть его код. В зависимости от результата проверки условия в переменную color_name передается результат разбиения строки либо копия аргумента функции. Однако затем в нижний регистр переводится не сама полученная строка, а исходный аргумент. В результате её не удастся найти в словаре цветов при наличии параметра прозрачности. Можем исправить эту строку так:

color_name = lowercase(color_name);

Лишние проверки условий

V547 Expression 'nearest_emergefull_d == 1' is always true. clientiface.cpp 363

void RemoteClient::GetNextBlocks (....){  ....  s32 nearest_emergefull_d = -1;  ....  s16 d;  for (d = d_start; d <= d_max; d++) {    ....      if (block == NULL || surely_not_found_on_disk || block_is_invalid) {        if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {          if (nearest_emerged_d == -1)            nearest_emerged_d = d;        } else {          if (nearest_emergefull_d == -1) // <=            nearest_emergefull_d = d;          goto queue_full_break;        }  ....  }  ....queue_full_break:  if (nearest_emerged_d != -1) { // <=    new_nearest_unsent_d = nearest_emerged_d;  } else ....}

Переменная nearest_emergefull_d в процессе работы цикла не меняется, и её проверка не влияет на ход выполнения алгоритма. Либо это результат неаккуратного copy-paste, либо с ней забыли провести какие-то вычисления.

V560 A part of conditional expression is always false: y > max_spawn_y. mapgen_v7.cpp 262

int MapgenV7::getSpawnLevelAtPoint(v2s16 p){  ....  while (iters > 0 && y <= max_spawn_y) {               // <=    if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) {      if (y <= water_level || y > max_spawn_y)          // <=        return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point      // y + 1 due to biome 'dust'      return y + 1;    }  ....}

Значение переменной 'y' проверяется перед очередной итерацией цикла. Последующее, противоположное ей, сравнение всегда вернет false и, в целом, не влияет на результат проверки условия.

Потеря проверки указателя

V595 The 'm_client' pointer was utilized before it was verified against nullptr. Check lines: 183, 187. game.cpp 183

void gotText(const StringMap &fields){  ....  if (m_formname == "MT_DEATH_SCREEN") {    assert(m_client != 0);    m_client->sendRespawn();    return;  }  if (m_client && m_client->modsLoaded())    m_client->getScript()->on_formspec_input(m_formname, fields);}

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

Бит или не бит?

V616 The '(FT_RENDER_MODE_NORMAL)' named constant with the value of 0 is used in the bitwise operation. CGUITTFont.h 360

typedef enum  FT_Render_Mode_{  FT_RENDER_MODE_NORMAL = 0,  FT_RENDER_MODE_LIGHT,  FT_RENDER_MODE_MONO,  FT_RENDER_MODE_LCD,  FT_RENDER_MODE_LCD_V,  FT_RENDER_MODE_MAX} FT_Render_Mode;#define FT_LOAD_TARGET_( x )   ( (FT_Int32)( (x) & 15 ) << 16 )#define FT_LOAD_TARGET_NORMAL  FT_LOAD_TARGET_( FT_RENDER_MODE_NORMAL )void update_load_flags(){  // Set up our loading flags.  load_flags = FT_LOAD_DEFAULT | FT_LOAD_RENDER;  if (!useHinting()) load_flags |= FT_LOAD_NO_HINTING;  if (!useAutoHinting()) load_flags |= FT_LOAD_NO_AUTOHINT;  if (useMonochrome()) load_flags |=     FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO | FT_RENDER_MODE_MONO;  else load_flags |= FT_LOAD_TARGET_NORMAL; // <=}

Макрос FT_LOAD_TARGET_NORMAL разворачивается в ноль, и побитовое "или" не будет устанавливать никакие флаги в load_flags, ветка else может быть убрана.

Округление целочисленного деления

V636 The 'rect.getHeight() / 16' expression was implicitly cast from 'int' type to 'float' type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double)(X) / Y;. hud.cpp 771

void drawItemStack(....){  float barheight = rect.getHeight() / 16;  float barpad_x = rect.getWidth() / 16;  float barpad_y = rect.getHeight() / 16;  core::rect<s32> progressrect(    rect.UpperLeftCorner.X + barpad_x,    rect.LowerRightCorner.Y - barpad_y - barheight,    rect.LowerRightCorner.X - barpad_x,    rect.LowerRightCorner.Y - barpad_y);}

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

Подозрительная последовательность операторов ветвления

V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. treegen.cpp 413

treegen::error make_ltree(...., TreeDef tree_definition){  ....  std::stack <core::matrix4> stack_orientation;  ....    if ((stack_orientation.empty() &&      tree_definition.trunk_type == "double") ||      (!stack_orientation.empty() &&      tree_definition.trunk_type == "double" &&      !tree_definition.thin_branches)) {      ....    } else if ((stack_orientation.empty() &&      tree_definition.trunk_type == "crossed") ||      (!stack_orientation.empty() &&      tree_definition.trunk_type == "crossed" &&      !tree_definition.thin_branches)) {      ....    } if (!stack_orientation.empty()) {                  // <=  ....  }  ....}

Здесь последовательности else-if в алгоритме генерации деревьев. Посередине очередной блок if находится на одной строке с закрывающей предыдущий else скобкой. Возможно, код работает правильно: до этого if-а создаются блоки ствола, а следом листьев; а может быть пропустили else. Наверняка это сказать может только разработчик.

Неправильная проверка выделения памяти

V668 There is no sense in testing the 'clouds' pointer against null, as the memory was allocated using the 'new' operator. The exception will be generated in the case of memory allocation error. game.cpp 1367

bool Game::createClient(....){  if (m_cache_enable_clouds) {    clouds = new Clouds(smgr, -1, time(0));    if (!clouds) {      *error_message = "Memory allocation error (clouds)";      errorstream << *error_message << std::endl;      return false;    }  }}

В случае, если new не сможет создать объект, будет брошено исключение std::bad_alloc, и оно должно быть обработано try-catch блоком. А проверка в таком виде бесполезна.

Чтение за границей массива

V781 The value of the 'i' index is checked after it was used. Perhaps there is a mistake in program logic. irrString.h 572

bool equalsn(const string<T,TAlloc>& other, u32 n) const{  u32 i;  for(i=0; array[i] && other[i] && i < n; ++i) // <=    if (array[i] != other[i])      return false;  // if one (or both) of the strings was smaller then they  // are only equal if they have the same length  return (i == n) || (used == other.used);}

Происходит обращение к элементам массивов перед проверкой индекса, что может привести к ошибке. Возможно, стоит переписать цикл так:

for (i=0; i < n; ++i) // <=  if (!array[i] || !other[i] || array[i] != other[i])    return false;

Другие ошибки

Данная статья посвящена анализу pull request-ов в Azure DevOps и не ставит целью провести подробный обзор ошибок проекта Minetest. Здесь выписаны только некоторые фрагменты кода, которые мне показались интересными. Предлагаем авторам проекта не руководствоваться этой статьёй для исправления ошибок и выполнить более тщательный анализ предупреждений, которые выдаст PVS-Studio.

Заключение


Благодаря гибкой конфигурации в режиме командной строки, анализ PVS-Studio может быть встроен в самые разнообразные сценарии CI/CD. А правильное использование доступных ресурсов окупается увеличением производительности.

Нужно отметить, что режим проверки pull request-ов доступен только в Enterprise редакции анализатора. Чтобы получить демонстрационную Enterprise лицензию, укажите это в комментарии при запросе лицензии на странице скачивания. Более подробно о разнице между лицензиями можно узнать на странице заказа PVS-Studio.


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Alexey Govorov. PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents.
Подробнее..

Анализ merge requestов в GitLab с помощью PVS-Studio для C

24.07.2020 10:04:54 | Автор: admin
image1.png

Любите GitLab и не любите ошибки? Хотите повысить качество исходного кода? Тогда вы попали по адресу. Сегодня мы расскажем, как настроить C# анализатор PVS-Studio для проверки merge request'ов. Всем единорожного настроения и приятного чтения.

PVS-Studio это инструмент для выявления ошибок и потенциальных уязвимостей в исходном коде программ, написанных на языках C, C++, C# и Java. Работает в 64-битных системах на Windows, Linux и macOS. Может анализировать код, предназначенный для 32-битных, 64-битных и встраиваемых ARM платформ.

Кстати, у нас состоялся релиз PVS-Studio 7.08, в котором мы сделали много всего интересненького. Например:

  • анализатор C# под Linux и macOS;
  • плагин для Rider;
  • новый режим проверки списка файлов.

Режим проверки списка файлов


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

Для того чтобы проверить определенные файлы, необходимо указать флаг --sourceFiles (-f) и передать .txt со списком файлов. Выглядит это следующим образом:

pvs-studio-dotnet -t path/to/solution.sln -f fileList.txt -o project.json

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

Принцип проверки merge request


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

Вот так выглядит merge request до внедрения статического анализатора:

image2.png

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

image3.png

Анализируем changes2 и, если ошибок нет, принимаем merge request, а иначе отклоняем его.

Кстати, если вас интересует анализ коммитов и pull request'ов для C/C++, то вы можете почитать об этом здесь.

GitLab


GitLab веб-инструмент жизненного цикла DevOps с открытым исходным кодом, представляющий систему управления репозиториями кода для Git с собственной вики, системой отслеживания ошибок, CI/CD пайплайном и другими функциями.

Перед тем как приступить к реализации анализа merge request'ов необходимо зарегистрироваться и загрузить свой проект. Если вы не знаете, как это сделать, то предлагаю статью моего коллеги.

Примечание. Описываемый далее способ настройки окружения один из возможных. Цель показать шаги настройки необходимого для анализа окружения и запуска анализатора. Возможно, в вашем случае более оптимальным будет разделение этапов подготовки окружения (добавление репозиториев, установка анализатора) и анализа: например, подготовка Docker образов с необходимым окружением и их использование или какой-нибудь иной способ.

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

image4.png

Для работы анализатору требуется .NET Core SDK 3, поэтому перед установкой анализатора нужно добавить репозитории Microsoft, из которых будут установлены необходимые для анализатора зависимости. Добавление репозиториев Microsoft для различных дистрибутивов Linux описано в соответствующем документе.

Для установки PVS-Studio через пакетный менеджер также потребуется добавить репозитории PVS-Studio. Добавление репозиториев для различных дистрибутивов более подробно описано в соответствующем разделе документации.

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

Примечание. Обратите внимание, что для описываемого режима работы (анализ merge requests) нужна Enterprise лицензия. Поэтому, если вы хотите попробовать данный режим работы, в поле "Сообщение" не забудьте указать, что вам нужна именно Enterprise лицензия.

Если происходит merge request, то нам потребуется проанализировать только список измененных файлов, а иначе анализируем все файлы. После анализа нужно сконвертировать логи в нужный нам формат.

Теперь, имея перед глазами алгоритм работы, можно переходить к написанию скрипта. Чтобы это сделать, необходимо изменить файл .gitlab-ci.yml или, если его нет, создать. Для его создания нужно нажать на название вашего проекта -> Set up CI/CD.

image5.png

Вот теперь мы готовы к написанию скрипта. Давайте сначала напишем код, который установит анализатор и введет лицензию:

before_script:  - apt-get update && apt-get -y install wget gnupg   - apt-get -y install git  - wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb  - dpkg -i packages-microsoft-prod.deb  - apt-get update  - apt-get install apt-transport-https  - apt-get update    - wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -  - wget -O /etc/apt/sources.list.d/viva64.listhttps://files.viva64.com/etc/viva64.list  - apt-get update  - apt-get -y install pvs-studio-dotnet  - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY  - dotnet restore "$CI_PROJECT_DIR"/Test/Test.sln

Так как установка и активация должна происходить перед всеми другими скриптами, то используем специальную метку before_script. Немного поясню данный фрагмент.

Подготовка к установке анализатора:

  - wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb  - dpkg -i packages-microsoft-prod.deb  - apt-get update  - apt-get install apt-transport-https  - apt-get update

Добавление репозиториев PVS-Studio и анализатора:

  - wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -  - wget -O /etc/apt/sources.list.d/viva64.listhttps://files.viva64.com/etc/viva64.list  - apt-get update  - apt-get -y install pvs-studio-dotnet

Активация лицензии:

  - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY

$PVS_NAME имя пользователя.

$PVS_KEY ключ продукта.

Восстановление зависимостей проекта, где $CI_PROJECT_DIR полный путь до директории проекта:

  - dotnet restore "$CI_PROJECT_DIR"/Path/To/Solution.sln

Для корректного анализа проект должен успешно собираться, а его зависимости должны быть восстановлены (например, должны быть загружены необходимые NuGet пакеты).

Задать переменные окружения, содержащие лицензионную информацию, можно, нажав на Setting, а после на CI / CD.

image6.png

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

image7.png

Теперь можно переходить к анализу. Сначала добавим скрипт для полного анализа. В флаг -t передаем путь до solution, в флаг -o пишем путь до файла, в который будут записаны результаты анализа. Также нас интересует код возврата. В данном случае нам интересно, чтобы работа прекращалась, когда код возврата содержит информацию о том, что в ходе анализа были выданы предупреждения. Вот как выглядит данный фрагмент:

job:  script:  - exit_code=0  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -o PVS-Studio.json || exit_code=$?  - exit_code=$((($exit_code & 8)/8))  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi

Коды возврата работают по принципу битовой маски. Например, если в результате анализа были выданы предупреждения, то код возврата будет равен 8. Если лицензия истечёт в течение месяца, то код возврата будет равен 4. Если же в ходе анализа были обнаружены ошибки, а также лицензия истекает в течение месяца, в код возврата будут записаны оба значения: складываем числа вместе и получаем итоговый код возврата 8+4=12. Таким образом, проверяя соответствующие биты, можно получать информацию о различных состояниях во время анализа. Более подробно коды возврата описываются в разделе "Коды возврата pvs-studio-dotnet (Linux / macOS)" документа "Проверка проектов Visual Studio / MSBuild / .NET Core из командной строки с помощью PVS-Studio".

В данном случае нас интересуют все коды возврата, где фигурирует 8.

  - exit_code=$((($exit_code & 8)/8))

Мы получим 1, когда код возврата содержит интересующий нас бит числа, а иначе получим 0.

Настало время добавить анализ merge request. Перед тем как это сделать, подготовим место для скрипта. Нам необходимо, чтобы он выполнялся только тогда, когда происходит merge request. Выглядит это вот так:

merge:  script:  only:  - merge_requests

Перейдем к самому скрипту. Я столкнулся с тем, что виртуальная машина ничего не знает про origin/master. Поэтому помогаем ей немного:

  - git fetch origin

Теперь получим разницу веток и сохраняем результат в txt файл:

  - git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt

Где $CI_COMMIT_SHA хеш последнего коммита.

Далее запускаем анализ списка файлов, используя флаг -f. В него передаем полученный раннее .txt файл. Ну и по аналогии с полным анализом смотрим коды возврата:

  - exit_code=0  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f pvs-fl.txt -o PVS-Studio.json || exit_code=$?  - exit_code=$((($exit_code & 8)/8))  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi

Полный скрипт для проверки merge request будет выглядеть вот так:

merge:  script:  - git fetch origin  - git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt  - exit_code=0  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f pvs-fl.txt -o PVS-Studio.json || exit_code=$?  - exit_code=$((($exit_code & 8)/8))  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi  only:  - merge_requests

Остается только добавить конвертацию лога после того, как отработали все скрипты. Используем метку after_script и утилиту plog-converter:

after_script:  - plog-converter -t html -o eLog ./PVS-Studio.json

Утилита plog-converter это open source проект, который используется для преобразования отчета об ошибках анализатора в различные формы, например, HTML. Более подробное описание утилиты приводится в подразделе "Утилита Plog Converter" соответствующего раздела документации.

Кстати, если вы хотите удобно работать с .json отчётом локально из IDE, то предлагаю наш плагин для IDE Rider. Более подробно его использование описано в соответствующем документе.

Для удобства вот .gitlab-ci.yml целиком:

image: debianbefore_script:  - apt-get update && apt-get -y install wget gnupg   - apt-get -y install git  - wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb  - dpkg -i packages-microsoft-prod.deb  - apt-get update  - apt-get install apt-transport-https  - apt-get update    - wget -q -O - https://files.viva64.com/etc/pubkey.txt | apt-key add -  - wget -O /etc/apt/sources.list.d/viva64.listhttps://files.viva64.com/etc/viva64.list  - apt-get update  - apt-get -y install pvs-studio-dotnet  - pvs-studio-analyzer credentials $PVS_NAME $PVS_KEY  - dotnet restore "$CI_PROJECT_DIR"/Test/Test.slnmerge:  script:  - git fetch origin  - git diff --name-only origin/master $CI_COMMIT_SHA > pvs-fl.txt  - exit_code=0  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -f pvs-fl.txt -o PVS-Studio.json || exit_code=$?  - exit_code=$((($exit_code & 8)/8))  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi  only:  - merge_requestsjob:  script:  - exit_code=0  - pvs-studio-dotnet -t "$CI_PROJECT_DIR"/Test/Test.sln -o PVS-Studio.json || exit_code=$?  - exit_code=$((($exit_code & 8)/8))  - if [[ $exit_code == 1 ]]; then exit 1; else exit 0; fi  after_script:  - plog-converter -t html -o eLog ./PVS-Studio.json

Как только добавили все в файл, нажимаем на Commit changes. Для того чтобы посмотреть, что все правильно, заходим в CI/CD -> Pipelines -> Running. Откроется окно виртуальной машины, в конце которой должно быть следующее:

image8.png

Увидели Job succeeded успех, все прекрасно. Теперь можно и протестировать сделанное.

Примеры работы


Для примера работы создадим простой проект (в master) в котором будет несколько файлов. После этого в другой ветке изменим только один файл и попробуем сделать merge request.

Рассмотрим два случая: когда измененный файл содержит ошибку и когда нет. Сначала пример с ошибкой.

Допустим, в master ветке есть файл Program.cs, который не содержит ошибок, а в другой ветке разработчик добавил ошибочный код и хочет сделать merge request. Какую именно ошибку он допустил не столь важно, главное, что она есть. Например, забыл оператор throw (да, так ошибаются):

void MyAwesomeMethod(String name){  if (name == null)    new ArgumentNullException(....);  // do something  ....}

Посмотрим на результат анализа примера с ошибкой. Также чтобы убедиться в том, что только один файл был проанализирован, я добавил флаг -r в строку запуска pvs-studio-dotnet:

image9.png

Мы видим, что анализатор нашел ошибку и не позволил сделать слияние веток.

Проверяем пример без ошибки. Исправляем код:

void MyAwesomeMethod(String name){  if (name == null)    throw new ArgumentNullException(....);  // do something  ....}

Результаты анализа merge request:

image10.png

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

Заключение


Отсеивать плохой код до слияния веток это очень удобно и приятно. Поэтому, если вы пользуетесь CI/CD, попробуйте встроить статический анализатор для проверки. Тем более что делается это достаточно просто.

Спасибо за внимание.


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Nikolay Mironov. Analysis of merge requests in GitLab using PVS-Studio for C#.
Подробнее..

Материалы митапа для андроид-инженеров поиск проблем сборки, защита от них и работа с Gradle

16.03.2021 18:09:12 | Автор: admin

Недавно прошёл наш Android meetup, где ребята из платформенной команды Авито делились своим опытом работы с Gradle, показывали способы защиты от частых проблем при сборке проектов и рассказывали о нашем подходе к решению проблем.

Собрали в посте видеозаписи выступлений с таймкодами и ссылки на презентации спикеров.

Gradle в 2021: сonvention plugins workshop Дмитрий Воронин

Воркшоп о способе организации проектов,который позиционируется командой Gradle как идиоматический.

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

00:00 Представление спикера и темы

05:27 Проект, который будет примером в воркшопе

06:44 Лайвкодинг: пошаговая оптимизация проекта

28:31 Ответы на вопросы

Полезные ссылки:

Lint для сборки: как защищаться от проблем при сборке проекта Евгений Кривобоков

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

00:00 Представление спикера и темы

01:38 Какие бывают проблемы

09:05 Как контролировать окружение

14:16 Пример специфической проблемы для конкретного проекта и её решения

20:04 Зачем вообще писать свои проверки

22:35 Ответы на вопросы

Посмотреть презентацию Евгения

Gradle build scan на коленке Сергей Боиштян

На боевом примере Сергей разбирает, как мы упростили поиск ошибок в своих CI-сборках. Вы узнаете, как мы применяем продуктовый подход в решении проблем и немного о том, как работаем с Gradle.

Доклад будет полезен тимлидам в больших командах, разработчикам, которые настраивают CI/CD и разработчикам, которые решают любого рода проблемы.

00:00 Представление спикера, темы и её пользы

04:12 Поиск проблемы: разбираем на примере падения сборки

06:51 Определяем приоритет задач по RICE

14:36 Как мы искали решение проблемы

18:30 Пишем прототип с помощью TestProjectGenerator

26:11 Версия инструмента 1.0

30:30 Отдаём инструмент пользователям и смотрим на результат

34:02 Сравнение: как было и как стало

36:52 Ответы на вопросы

Посмотреть презентацию Сергея

На этом всё, до встречи на новых митапах!

Подробнее..

Перевод Вышел GitLab 13.1 с управлением оповещениями, качеством кода и улучшениями для безопасности и соответствия требованиям

10.07.2020 14:07:02 | Автор: admin

Картинка для привлечения внимания


Релиз GitLab 13.1 уже доступен! Улучшения нового релиза включают расширенное управление уведомлениями и инструменты, которые помогут вам контролировать и улучшать качество кода, а также другие способы поддержания безопасности и соответствия вашего кода требованиям.


Автоматизируйте и расширяйте управление оповещениями


Оповещения необходимы для обслуживания приложения, но изучение и сортировка всех выдаваемых оповещений могут значительно снизить производительность и время отклика. Система управления оповещениями в GitLab объединяет и упорядочивает оповещения всех ваших сервисов, упрощая их анализ и устранение, повышая производительность и помогая вам сразу же приступить к изучению и ликвидации критических проблем. Ключевые нововведения в 13.1 включают назначение оповещений, интеграцию Slack и создание GitLab To-Dos при назначении оповещений.


Улучшение качества кода


Скорость развертывания имеет значение только в том случае, если вы развертываете качественный код. Благодаря приоритизации тестов для недавно измененного кода разработчики смогут сразу же начать устранять ошибки, не выполняя при этом весь набор тестов. Отслеживание покрытия кода с течением времени позволяет выявить тенденции качества как для разработчиков, так и для менеджеров, а встроенный code intelligence увеличивает скорость и точность ревью кода, интегрируя справочные материалы непосредственно в GitLab.


Укрепление и повышение уровня безопасности и соответствия требованиям


Безопасность важна для всех, и мы стремимся сократить барьеры на пути к полностью безопасному и совместимому SDLC. Вот почему мы рады сообщить, что мы перевели SAST-сканирование Brakeman в план Core, предоставляя возможность сканировать исходный код на наличие известных уязвимостей каждому Rails разработчику, независимо от уровня плана. Для организаций, ориентированных на соблюдение требований, мы добавили пользовательский интерфейс управления правилами для сетевых правил контейнеров, а также включили экспорт уязвимостей на уровне группы в CSV-файл для аудита или дальнейшего внутреннего анализа. Кроме того, мы внесли пару UX-улучшений в панель безопасности, добавив сохранение фильтров и иконки состояния тикетов для поддержания контекста во время работы в этой панели.


И это еще не все!


Это лишь небольшая выборка из обновлений релиза 13.1. В нем мы также достигли важного рубежа в отношении сотрудничества с сообществом. В рамках этого релиза были приняты более 300 мерж-реквестов (в русской локализации GitLab запросы на слияние) от нашего обширного сообщества, и мы высоко ценим вклад каждого из вас! Читайте дальше, чтобы узнать больше о других замечательных улучшениях, таких, как виджеты мерж-реквестов для тестирования доступности, возможность пометить обсуждение в дизайне как решенное, уведомления об успешном завершении конвейера и многие другие!


Если вы хотите узнать, что вас ждет в следующем релизе, посмотрите наше видео по релизу 13.2.


Приглашаем на наши встречи.


GitLab MVP badge


MVP этого месяца Jacopo Beschi


Jacopo добавил новые уведомления по электронной почте после восстановления сборки конвейера. До сих пор GitLab отправлял уведомления по электронной почте, когда конвейер завершался неуспешно, но когда его работа восстанавливалась, никаких уведомлений об исправлении не отправлялось. Разработчикам приходилось неоднократно перезагружать страницу мерж-реквеста или конвейера, чтобы проверить его статус. Благодаря этому замечательному вкладу проблема была решена, что избавило разработчиков от ненужных хлопот.


Работа над этой фичей заняла около 8 месяцев и Jacopo справился с этой задачей отлично! Он получил подтверждение от 5 различных ревьюверов, отличные отклики от нас в GitLab и большой интерес от пользователей: более 30 голосов за этот тикет и почти 70 активных дискуссий, связанных с ним.


Jacopo, спасибо за этот потрясающий вклад, мы очень его ценим!


Основные фичи в GitLab 13.1


Управление оповещениями в GitLab


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


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


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


В релизе 13.2 и далее мы планируем улучшить рабочие процессы оповещений и реагирования на инциденты с помощью интеграции с PagerDuty, отображения соответствующих метрик и логов оповещений, ассоциирования с перечнями задач (runbook) и создания специального Alert Integration Builder, чтобы ваши операторы могли самостоятельно обслуживать и беспрепятственно интегрировать GitLab с любыми инструментами мониторинга. Ознакомиться с ходом нашей работы и предложить свои идеи для будущих улучшений можно в эпике (в русской локализации GitLab цель) по управлению оповещениями.


Manage IT Alerts in GitLab


Документация по управлению оповещениями и оригинальный эпик.


Настройка стратегий переключения фич для разных окружений


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Release


В этом релизе мы переработали пользовательский интерфейс переключаемых фич (feature flags), чтобы включить в него настройку стратегий для нескольких окружений. Без этого было намного сложнее управлять переключаемыми фичами и настраивать стратегии по мере увеличения количества окружений. Это решение позволяет более свободно создавать и применять их.


Set Feature Flag Strategy Across Environments


Документация по созданию переключаемых фич и оригинальный тикет.


Виджет тестирования доступности в мерж-реквесте


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


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


С GitLab 13.1 вы можете добавить в мерж-реквесты виджет, который будет подробно описывать ухудшение доступности, связанное с измененными страницами. Это сразу же покажет разработчикам влияние их изменений, что поможет предотвратить ухудшение доступности до слияния и развертывания изменений.


Accessibility Testing Merge Request Widget


Документация по тестированию на доступность и оригинальный тикет.


Возможность пометить обсуждение в дизайне как решенное


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


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


С релизом 13.1 вы сможете отметить любой комментарий как Решенный (Resolved), что означает, что обсуждение по нему завершено. Пины завершенных обсуждений исчезнут из дизайна, так что вы сможете сосредоточиться на том, что осталось. И, конечно же, если вам нужно что-то пересмотреть, все ваши завершенные обсуждения будут доступны в области Решенные обсуждения (Resolved Comment) в нижней части боковой панели. Там вы сможете найти их и проверить, какая ревизия была применена в данной точке.


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


Mark any Design thread as resolved


Документация по завершению обсуждений в дизайнах и оригинальный тикет.


Ревью мерж-реквестов перенесены в Core


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


Первоначально представленные в GitLab 11.4 в плане Premium, ревью мерж-реквестов позволяют ревьюверам отправлять несколько комментариев одновременно, что снижает количество оповещений для автора мерж-реквеста, а также обеспечивают более целостный и упорядоченный процесс ревью.


С тех пор мы пересмотрели место этой фичи в нашей стратегии определения планов, нацеленной на покупателя. Теперь мы рады объявить, что в рамках релиза 13.1 эта фича перенесена в план Core.


Merge Request Reviews moved to Core


Документация по ревью мерж-реквестов и оригинальный тикет.


Code Intelligence


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


Ревью кода важный процесс, который требует понимания предлагаемых изменений и окружающего их кода, что позволяет убедиться в том, что они были сделаны в удобном для поддержания порядка виде. Во время написания нового кода или просмотра изменений в существующем разработчикам необходимо легко переходить к определениям, чтобы лучше понимать контекст. Особенно это важно при ревью нового кода, а также изменений в мерж-реквестах. Однако настройка просматриваемых определений обычно означала настройку внешних инструментов и ресурсов или же использование специализированной IDE. Для работы с GitLab теперь они вам не понадобятся.


Мы вдохновлялись огромной работой, проделанной нашими коллегами из Sourcegraph, и использовали формат LSIF. Благодаря этому встроенный в GitLab Code Intelligence теперь можно добавить в любой проект с помощью нового задания в файле .gitlab-ci.yml. Это задание будет отвечать за LSIF-отчет, после генерации которого вы будете видеть доступные действия Code Intelligence при наведении курсора на объекты в коде. С релизом 13.1 вам больше не понадобятся сторонние инструменты или IDE для этого.


Будущие итерации будут включать в себя возможность поиска ссылок, а также поддержку API. Вы можете следить за обновленями в эпике Code Intelligence.


Code Intelligence


Документация по Code Intelligence в GitLab и оригинальный тикет.


Управление переключаемыми фичами через списки пользователей


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Release


GitLab раньше уже поддерживал возможность контролировать развертывание фич на основе ID пользователей. Однако многократно добавлять пользователей для каждой фичи или окружения может быть утомительно. Чтобы сделать этот процесс удобнее, мы добавили новую стратегию для переключаемых фич списки. Списки пользователей создаются и модифицируются с помощью API. После создания списка выберите стратегию list для вашей переключаемой фичи и соответствующий список. Если у вас уже есть созданные списки, вы сразу же сможете ими воспользоваться.


Control Feature Flags with User Lists


Документация по переключаемым фичам и оригинальный тикет.


График изменения покрытия кода в проекте


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


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


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


Graph code coverage changes over time for a project


Документация по отслеживанию покрытия кода и оригинальный тикет.


Специальное задание CI для управления требованиями


(ULTIMATE, GOLD) Стадия цикла DevOps: Plan


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


Мы рады представить первый шаг в этом направлении: возможность настроить в рамках стандартного CI-конвейера задания, которые при запуске будут отмечать все существующие требования как выполненные. Такое CI-задание может быть как ручным, так и автоматическим. А еще, как и другие задания CI, его можно настроить на разрешение неудачных выполнений (allow-failure), чтобы это задание не блокировало успешное завершение всего конвейера.



Документация по настройке выполнения требований и оригинальный эпик.


Другие улучшения в GitLab 13.1


Параметр expires_at в конечной точке /user/keys


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


Спасибо Petar Prokic (@pprokic) за этот вклад от сообщества!


Конечные точки в API пользователей /user/keys и /users/:id/keys теперь поддерживают опциональный параметр expires_at для определения даты истечения срока действия SSH-ключей. Это изменение поможет пользователям и организациям управлять последствиями в случаях скомпрометированных учетных записей в контролируемом окружении.


Документация по добавлению SSH-ключей и оригинальный мерж-реквест.


Конечная точка projects для API аудита событий


(STARTER, PREMIUM, ULTIMATE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


Спасибо Julien Millau (@devnied) за этот вклад от сообщества!


В API событий аудита в GitLab появилась новая конечная точка для проектов, что позволит владельцам групп проверять конкретные изменения данных проекта. Это изменение облегчает поиск и получение данных, необходимых для управления вашими программами соответствия требованиям, а также позволяет создавать инструменты, необходимые для проверки и отслеживаемости ваших проектов в GitLab.


Документация по аудиту событий и оригинальный тикет.


Тренды и подробности в аналитике тикетов


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Manage


Аналитика тикетов позволяет быстро выявлять тенденции в данных тикетов. Чтобы расширить эту возможность, мы добавили таблицу, в которой перечислены основные детали, такие как давность тикета, статус, майлстоун (в русской локализации GitLab этап), вес, срок выполнения, назначенные исполнители, а также автор тикета. Благодаря этому у пользователей будет более полное представление о процессе выполнения их запроса, что идет не по графику и какие конкретные тикеты выбиваются из тренда.


Explore Trends & Details in Issue Analytics


Документация по аналитике тикетов и оригинальный тикет.


Ограничение доступа на основе IP-адресов теперь в Premium


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Manage


Ограничение доступа на основе IP-адресов теперь доступно для планов Premium и Silver. Эта фича позволяет вам ограничить доступ к группам и их контенту по одной или нескольким IP-подсетям. Включение ограничения доступа по IP гарантирует, что ваши данные не будут покидать пределы территории, не блокируя при этом доступ ко всему инстансу.


Документация по ограничению доступа по IP-адресам и оригинальный тикет.


Заголовок тикета теперь зафиксирован на странице


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Plan


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


Issue titles are now sticky


Документация по тикетам и оригинальный тикет.


Поддержка EditorConfig в Web IDE


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


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


При открытии файла Web IDE будет искать файл с именем .editorconfig в текущем каталоге и во всех родительских каталогах. Если такой файл будет найден и в нем есть настройки, соответствующие пути к открытому файлу, то эти настройки будут применены к нему. Web IDE обеспечивает поддержку большинства широко поддерживаемых функций EditorConfig, за исключением charset.


Документация по настройке Web IDE и оригинальный тикет.


Скрытие вступительной части YAML в статическом редакторе сайтов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


Статические генераторы сайтов используют первые несколько строк (вступительную часть, "front matter") в начале файла Markdown, между двумя строками ---, для форматирования, настройки или парсинга страницы. Вступительная часть не должна отображаться вместе с содержимым страницы и должна при этом соответствовать определенным правилам форматирования.


Статический редактор сайтов GitLab включает в себя обширный инструментарий редактирования контента, который разбирает синтаксис Markdown и отображает его в более привычном стиле. Однако вступительная часть, не предназначенная для отображения, ранее непреднамеренно отображалась, и ее редактирование с помощью визуального редактора могло привести к непредвиденным последствиям.


В релизе GitLab 13.1 наш редактор скрывает любые YAML-форматированные вступительные части, содержащиеся в начале файла Markdown, чтобы избежать путаницы и непреднамеренного изменения форматирования. Эта часть остается редактируемой в режиме Markdown, доступном для переключения в правом нижнем углу редактора статических сайтов.


Документация по статическому редактору сайтов и оригинальный тикет.


Вставка изображений в Markdown в Web IDE


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


При работе с Markdown-контентом в Web IDE часто требуется добавлять в него изображения. В большинстве редакторов это требует поиска нужного изображения, добавления его в файловую структуру и последующей ссылки на него с помощью синтаксиса Markdown.


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



Документация по Markdown в Web IDE и оригинальный тикет.


Фильтр конвейеров по статусу и имени тега


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


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


Документация по странице конвейеров и оригинальный тикет.


Переменные CI/CD для инстансов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


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


Документация по переменным CI/CD для инстансов и оригинальный тикет.


Шаблоны для упрощения первоначальной настройки ключевых слов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


Понять, как использовать новое ключевое слово rules, может быть сложно, особенно если ранее вы пользовались только only/except. Эти два ключевых слова отличаются принципиально: rules создает конвейер мерж-реквеста по умолчанию, а only/except этого не делает.


Чтобы упростить начало работы с ключевым словом rules и помочь вам быстрее получить первый успешный запуск конвейера, мы добавили шаблоны для двух самых популярных конфигураций workflow: rules. Теперь вам будет намного проще начинать работу с ключевыми словами, и вы сможете сфокусироваться на том, что действительно важно.


Документация по шаблонам для ключевых слов и оригинальный тикет.


Скачивайте артефакты заданий проще и быстрее


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Secure


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


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


С GitLab 13.1 мы добавили поддержку скачивания следующих типов отдельных отчетов по артефактам:


  • доступность
  • архив
  • cobertura
  • качество кода
  • сканирование контейнера
  • dast
  • сканирование зависимостей
  • dotenv
  • junit
  • управление лицензиями
  • сканирование лицензии
  • lsif
  • метрики
  • производительность

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


Download job artifacts faster and easier


Документация по скачиванию артефактов и оригинальный тикет.


Экспорт списка уязвимостей с панелей безопасности группы


(ULTIMATE, GOLD) Стадия цикла DevOps: Secure


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


Просто перейдите на любую панель безопасности группы и кликните на новую кнопку Экспорт (Export). Ваш браузер автоматически начнет загрузку.


Export vulnerabilities list from Group Security Dashboards


Документация по экспорту уязвимостей с панели безопасности и оригинальный тикет.


Более явный поиск секретных ключей и новый отдельный шаблон поиска секретных ключей


(ULTIMATE, GOLD) Стадия цикла DevOps: Secure


Поиск секретных ключей вырос из под-фичи SAST до отдельной самостоятельной категории. Результаты поиска секретов теперь лучше видны: их можно увидеть в отдельном разделе в мерж-реквестах и во вкладках с информацией по безопасности конвейеров. Также поиск секретов теперь отображает статус конфигурации на странице настроек безопасности, а результаты поиска выводятся на панели безопасности проекта.


CI/CD конфигурация для поиска секретных ключей теперь предоставляется в отдельном шаблоне от GitLab и запускается как новый тип сканирования. Этот новый шаблон поиска секретных ключей теперь также включен в Auto DevOps. Мы рекомендуем вам использовать этот шаблон и затем убрать старое определение задания SAST secrets-sast из шаблона настройки SAST в файле SAST.gitlab-ci.yml. Мы сняли видео, которое объяснит вам процесс перехода на этот новый шаблон. Мы избавимся от старого определения SAST-задания по поиску секретных ключей в следующем релизе GitLab.



Документация по поиску секретных ключей и оригинальный эпик.


Сканирование SAST для Helm charts


(ULTIMATE, GOLD) Стадия цикла DevOps: Secure


Наш анализатор статического сканирования безопасности приложений (SAST) для манифестов Kubernetes теперь поддерживает Helm чарты. Это обновление также добавляет поддержку двух новых переменных окружения для точной настройки анализатора: KUBESEC_HELM_CHARTS_PATH и KUBESEC_HELM_OPTIONS.


Отдельное спасибо @agixid за вклад в разработку этой фичи!


SAST Scanning for Helm Charts


Документация по поддерживаемым языкам и фреймворкам и оригинальный тикет.


Документация по сине-зеленым развертываниям


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


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



Документация по сине-зеленым развертываниям и оригинальный тикет.


Уведомления об успешном завершении конвейера после неудачи


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


Каждый раз, когда конвейер завершается с ошибкой, вы автоматически получаете уведомление по email. Однако, когда после неудачи конвейер восстанавливается и завершается успешно, автоматическое уведомление не приходит, что заставляет вас вручную проверять статус конвейера. В этом релизе мы рады представить вам фичу от @jacopo-beschi, которая решает эту проблему путем автоматической отправки уведомления, когда конвейер после неудачи завершается успешно.


Документация по уведомлениям о событиях GitLab и оригинальный тикет.


Улучшенная авторизация для файла состояния Terraform под управлением GitLab


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Configure


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


Начиная с GitLab 13.1 мы расширили возможности автоматически генерируемого токена CI для поддержки учетных данных текущего пользователя. Этот токен разработан специально для запуска заданий по управлению состояниями Terraform, что позволяет вам запускать конвейеры с заданиями Terraform без дополнительных настроек.


Документация по файлам состояния Terraform под управлением GitLab и оригинальный тикет.


Назначение оповещений GitLab членам команды


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


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


Assign GitLab Alerts to team members


Документация по управлению оповещениями и оригинальный эпик.


Логирование назначений оповещений в системных заметках


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


Возможность проводить аудит оповещений важна для обратной связи и работы над улучшениями, однако в процессе устранения инцидентов редко находится время, чтобы задокументировать детали, которые понадобятся позже. В GitLab 13.0 мы добавили назначения оповещений членам команды в системные заметки на странице Оповещения (Alerts), чтобы вы могли обсудить их при ревью после инцидента.


Alert assignments logged in system notes


Документация по системным заметкам для оповещений и оригинальный тикет.


Отправка оповещений GitLab в Slack


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


Мы добавили новые команды для нашего сервиса Slack-уведомлений, чтобы вы могли пересылать в Slack оповещения GitLab о перебоях ответственным за проект, чтобы они могли начать совместную работу, не покидая свою центральную платформу для общения.


Документация по интеграции со Slack и оригинальный тикет.


Создание списков To-Do при назначении работы по оповещениям


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


Теперь вы можете назначать оповещения определенным членам команды, что поможет в организации оповещений, запущенных по триггеру, и делегированию расследования проблем. Добавление списка To-Do GitLab сообщит пользователям о том, что что-то требует их внимания.


Документация по назначению исполнителя по оповещению и оригинальный тикет.


Отображение внешних ссылок на панели метрик


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


Панели метрик наиболее полезны тогда, когда они позволяют добавлять больше деталей. В GitLab 13.1 вы сможете добавлять ссылки в меню More actions на вашей панели метрик. Так вы можете связать вашу панель метрик и панель управления с другими панелями метрик и инструментами устранения неполадок, которыми пользуется ваша команда.


Metric dashboard panels display external links


Документация по добавлению ссылок на панели Prometheus и оригинальный тикет.


Поддержка UTC для панелей метрик


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


GitLab 13.1 теперь позволяет панелям метрик отображать время в формате UTC, что позволяет членам распределенных команд видеть видеть одни и те же данные времени, независимо от того, где они находятся.


Metric dashboards now support UTC


Документация по изменению временной зоны на панели метрик и оригинальный тикет.


Панели задач с самомониторингом для пользователей Omnibus GitLab


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


В GitLab 13.1 пользователи Omnibus GitLab получат новую панель для проектов с самоуправлением. Эта панель управления будет работать из коробки и позволит проводить мониторинг состояния инстанса GitLab.



Документация по проектам с самомониторингом и оригинальный тикет.


Управление правилами сетевой безопасности контейнеров


(ULTIMATE, GOLD) Стадия цикла DevOps: Defend


С первым релизом пользовательского интерфейса для управления правилами сетевой безопасности контейнеров пользователи смогут легко сканировать список правил, применяемых в их проекте, и включать/выключать эти правила через пользовательский интерфейс. Вы можете посмотреть на новое управление правилами в Security & Compliance -> Threat Management -> Policies.


Policy Management for Container Network Policies


Документация по управлению правилами сетевой безопасности контейнеров и оригинальный эпик.


Сократилось время поиска через API


(STARTER, PREMIUM, ULTIMATE, BRONZE, SILVER, GOLD) Доступность


Если вы когда-нибудь пользовались API для поиска, то могли заметить, что для некоторых поисков время ответа могло достигать более 11000 мс. Очевидно, что это не очень эффективно.


В GitLab 13.1 мы оптимизировали некоторые запросы, решив проблему N+1 вызовов базы данных, и увидели 40%-е улучшение времени ответа. Поиск еще никогда не был таким быстрым!


Документация по поиску и оригинальный эпик.


Поиск со страницы проекта через выпадающее меню включает поиск по группе


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Доступность


В GitLab 13.1 при поиске со страницы проекта через выпадающее меню поиска вы теперь можете искать по группе, к которой принадлежит этот проект. До GitLab 13.1 результаты поиска не включали результаты в этой группе при поиске из проекта.


Search in a group from a project in the search box dropdown


Документация по расширенному глобальному поиску и оригинальный тикет.


Исправленные баги


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD)


Вот некоторые баги, которые мы исправили в релизе 13.1, и о которых стоит упомянуть:



Все исправления багов в GitLab 13.1 можно посмотреть здесь.


Добавление события аудита при создании ключа SSH через API


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Manage


Спасибо Rajendra Kadam (@raju249) за вклад в разработку этой фичи!


Теперь при создании для пользователя SSH-ключа через API самим пользователем или администратором, это действие будет залогировано в таблице событий аудита. Ранее эти действия не логировались, что создавало пробел в аудите учетных данных SSH для пользователя.


Документация по добавлению SSH ключей для пользователя и мерж-реквест.


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


(STARTER, PREMIUM, ULTIMATE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


Аналитика вкладов в разработку помогает командам понимать, как нагрузка распределяется между участниками. Ранее вклад пользователей, подтверждающих мерж-реквесты (approvers) никак не учитывался, несмотря на их значимую роль в обеспечении необходимого ревью. Таблица со вкладами пользователей в группе теперь включает столбец Approved MRs, с возможностью сортировки по числу подтвержденных мерж-реквестов.


Contribution Analytics now show approvals


Документация по сортировке в аналитике вкладов и оригинальный тикет.


Членство в группе для пользователей с разными почтовыми доменами


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Manage


В GitLab 13.1 владельцы группы теперь могут добавлять в белый список почтовые адреса пользователей, принадлежащие к разным доменам, а не только к одному. Это позволит проводить более гибкую настройку доступа к вашей группе.


Group membership allow list supports multiple email domains


Документация по ограничению доступа по доменам и оригинальный тикет.


Быстрое назначение исполнителей


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Plan.


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


Assign issues faster


Документация по назначению тикета через комментарии и оригинальный тикет.


Распределение операций чтения по кластеру Gitaly (бета)


(CORE, STARTER, PREMIUM, ULTIMATE) Стадия цикла DevOps: Create


Кластер Gitaly позволяет вам реплицировать репозитории Git на нескольких теплых нодах Gitaly, что повышает надежность путем устранения единичных точек отказа.


В GitLab 13.1 операции чтения Git можно распределять по актуальным репликам Gitaly. Это позволяет более эффективно использовать доступные ресурсы и может улучшить производительность.


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


Документация по распределенным операциям чтения и оригинальный эпик.


Автоматическое аварийное переключение кластера Gitaly включено по умолчанию


(CORE, STARTER, PREMIUM, ULTIMATE) Стадия цикла DevOps: Create


Кластер Gitaly улучшает отказоустойчивость хранилища Git в GitLab: устраняет единичные точки отказа, обнаруживает сбои и автоматически переключается на реплику. Начиная с GitLab 13.1, когда Gitaly Cluster настроен, по умолчанию включаются выбор ноды-лидера для SQL и аварийное переключение.


Если во время аварийного переключения обнаруживаются нереплицированные операции записи, кластер переводится в режим только для чтения, чтобы предотвратить split brain (синдром расщепленного мозга). В будущем сильная согласованность потребует успешной операции записи на нескольких нодах Gitaly, прежде чем ответить сигналом об успехе, что предотвратит эту проблему и необходимость помечать кластер как доступный только для чтения.


Ранее в GitLab 13.0 вместо аварийного переключения по умолчанию был выбор лидера в памяти.


Документация по аварийному переключению и выбору лидера и оригинальный тикет.


Добавление и предварительный просмотр изображений в редакторе статических сайтов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


Редактор статических сайтов предоставляет немедленную визуальную обратную связь при написании контента в Markdown и интуитивно понятные элементы управления форматированием для обеспечения согласованной и точной разметки. Однако в GitLab 13.0 визуальное редактирование ограничивалось текстом.


В GitLab 13.1 вы можете быстро добавлять изображения на свои страницы с помощью редактора статических сайтов. После нажатия иконки Изображение на панели форматирования просто укажите URL, добавьте необязательный текст ALT, и все готово. Ссылка может вести на изображения, уже размещенные в вашем проекте, ресурс, размещенный в сети доставки контента (CDN), или любой другой внешний URL. Редактор создает миниатюры для предварительного просмотра, так что вы cможете убедиться, что добавили правильное изображение и нет ссылок на отсутствующие изображения.


Документация по редактору статических сайтов и оригинальный тикет.


Терминал Web IDE и синхронизация файлов перенесены в Core


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


GitLab 11.6 представил Веб-терминалы для Web IDE. Через несколько релизов была добавлена синхронизация файлов с веб-терминалом, позволяющая веб-терминалу взаимодействовать с изменениями, внесенными через Web IDE.


Ранее в 2020 году GitLab решил переместить 18 фич в опенсорсный план Core нашего продукта. В этом релизе GitLab мы завершили работу по перемещению в Core как веб-терминала, так и утилиты синхронизации файлов. Мы рады предоставить эти фичи большему числу пользователей и посмотреть, для каких ситуаций и рабочих процессов вы можете их использовать.



Документация по интерактивным веб-терминалам для Web IDE и оригинальный тикет.


GitLab Runner 13.1


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


Мы также выпускаем обработчик заданий GitLab версии 13.1. GitLab Runner это легкий, масштабируемый агент, который запускает ваши сборочные задания и отправляет результаты обратно в инстанс GitLab. Обработчик заданий GitLab работает совместно с GitLab CI/CD, опенсорсной службой непрерывной интеграции, входящей в состав GitLab.


Что нового:



Исправления ошибок



Список всех изменений находится в changelog GitLab Runner.


Документация по обработчику заданий GitLab.


Сначала выполняются тесты для измененных файлов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


Как разработчик, вы хотите быстро получать обратную связь о ваших изменениях, включая результаты недавно написанных тестов. В крупных проектах, таких как GitLab, это может быть особенно трудно, когда приходится ждать до 45 минут только для того, чтобы увидеть, что новый юнит-тест проходит или что еще хуже терпит неудачу. Эта медлительность может привести к тому, что вы решите совсем пропустить разработку автотестов.


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


Документация по тестированию со скорейшим выявлением ошибок и оригинальный тикет.


Используйте метаданные, чтобы понять, как создаются ваши пакеты NuGet


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Package


Когда пакет NuGet загружается в GitLab, задание открывает архив и читает файл .nuspec. Имя и версия пакета извлекаются сразу, но некоторые другие поля, например dependencies, project_url и tags, доступны, но не извлечены. Эти поля полезны для понимания того, как был построен пакет и каковы его зависимости.


В GitLab 13.1 мы рады сообщить, что теперь эти метаданные тоже будут извлечены при загрузке и добавлены в пользовательский интерфейс, чтобы вы могли проверить, что пакет собран правильно.


Документация по просмотру дополнительной информации о пакете и оригинальный тикет.


Динамические значки состояния тикета на панелях безопасности


(ULTIMATE, GOLD) Стадия цикла DevOps: Secure


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


Dynamic Issue status icons on Security Dashboards


Документация по панелям безопасности и оригинальный тикет.


На панелях безопасности сохраняются фильтры


(ULTIMATE, GOLD) Стадия цикла DevOps: Secure


GitLab 13.0 представил отдельные страницы уязвимостей как важный шаг на пути к будущему управлению уязвимостями. Однако переход от всплывающих информационных блоков к отдельным страницам потребовал некоторой переработки пользовательского интерфейса.


Переход от панелей безопасности к странице уязвимостей и обратно ранее удалял все фильтры, примененные на панели. Ваши отзывы нам ясно дали понять, что улучшение этого перехода улучшит сортировку уязвимостей и управление ими. Ваши фильтры теперь сохраняются при перемещении между страницами уязвимостей и панелью безопасности, что значительно повышает эффективность управления уязвимостями. Это также соответствует знакомому шаблону UX в других местах GitLab, например при управлении списком To-Do.


Документация по панелям безопасности и оригинальный тикет.


Анализатор SAST для Rails теперь доступен для всех


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Secure


Мы хотим помочь разработчикам писать классный код и меньше беспокоиться о распространенных ошибках безопасности. Статическое тестирование безопасности приложений (SAST) помогает предотвратить уязвимости безопасности, позволяя разработчикам легко выявлять типичные проблемы безопасности по мере разработки кода и заранее их предотвращать. В рамках наших обязательств по управлению GitLab мы делаем наш анализатор SAST для Rails (Brakeman) доступным для каждого плана GitLab. Это позволит всем пользователям GitLab, работающим с Rails, использовать сканирования безопасности SAST для своих проектов. Мы продолжим переводить другие анализаторы SAST с открытым исходным кодом (OSS) в план Core. Вы можете следить за нашим эпиком SAST to Core, чтобы узнать, когда станут доступны другие анализаторы, и внести свой вклад в этот процесс.


Rails SAST analyzer available for all


Документация по поддерживаемым SAST языкам и фреймворкам и оригинальный тикет.


Поддержка API для установки нескольких стратегий переключаемых фич


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Release


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


Документация по переключаемым фичам и изменениям в их поведении в GitLab 13.0 и 13.1 и оригинальный тикет.


Встроенная ссылка на руководство по развертыванию в AWS


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


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


In-product link to guidance for deploying to AWS


Документация по развертыванию в AWS и оригинальный тикет.


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


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


Теперь GitLab позволяет вам удобно указать тип ссылки на ресурс, добавленный в ваш релиз, с помощью выпадающего меню. Ранее, если вы добавляли ссылки к релизу, вы не могли указать тип ресурса. Теперь вы можете выбрать тип ресурса из следующих вариантов: Runbook, Package, Image или Other.


Specify asset types for Release links


Документация по ссылкам на ресурсы и оригинальный тикет.


Упрощенная настройка для интеграции Terraform


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Configure


Вы можете проще запускать фичи Terraform, интегрированные в GitLab, с одним из образов Terraform, предоставленных GitLab. Образы Terraform в GitLab расширяют официальные образы Terraform для бета-версий Terraform 0.12 и 0.13, включая простые команды для использования виджетов для мерж-реквестов без раздувания ваших файлов YAML для CI/CD.


Документация по пользовательской инфраструктуре и оригинальный тикет.


Сортировка столбцов для списка оповещений


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


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


Column sorting for Alert list


Документация по управлению оповещениями и их сортировке и оригинальный тикет.


Легенды в виде таблицы на панели метрик


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


Без соответствующего контекста график бывает сложно понять. В GitLab 13.1 мы упростили сравнение данных при просмотре графиков, добавив легенду графика в виде таблицы.


Metric dashboard legends in table format


Документация по настройке панели метрик и оригинальный тикет.


На панели метрик отображаются ссылки на связанные панели


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


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



Документация по добавлению ссылок на панели метрик и оригинальный эпик.


Проверка конфигурации панели метрик


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Monitor


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


Metrics dashboard configuration validation


Документация по проверке конфигурации панели метрик и оригинальный тикет.


На страницах статуса теперь показываются изображения


(ULTIMATE, GOLD) Стадия цикла DevOps: Monitor


Изображения, включенные в описания тикетов, опубликованных на страницах состояния GitLab, теперь отрисовываются, предоставляя содержательный контекст клиентам, пользователям и заинтересованным сторонам, чтобы помочь им принять решение о том, как справиться с перебоями и снижением производительности. Если вы одновременно можете посмотреть и текст, и изображение, вам будет проще понять, что происходит. А это способствует доверию и уверенности пользователей.


Документация по настройке страниц статуса и оригинальный тикет.


Улучшения в GitLab Helm chart


(CORE, STARTER, PREMIUM, ULTIMATE) Доступность


  • Шаблон extraEnv теперь поддерживается в GitLab Helm charts. Это позволяет вам предоставлять дополнительные переменные окружения, такие как прокси-серверы, как для определенных чартов GitLab, так и глобально для всех чартов. Обратитесь к документации по глобальным настройкам или документации по подчартам, чтобы подробно узнать, как реализовать extraEnv.
  • Пользовательские аннотации, определенные в разделе deployment глобальных настроек в values.yml, теперь доступны во всех подчартах GitLab. Аннотации развертывания позволяют предоставлять доступ на уровне развертывания, а не на уровне ноды, например разрешая развертыванию читать из корзины Amazon S3, не давая всей ноде доступа к этой корзине. Подробнее о настройке аннотаций развертывания смотрите в документации по аннотациям.
  • Библиотеки PostgreSQL и клиент в образах контейнера GitLab обновились до PostgreSQL 12, что позволяет использовать больше версий PostgreSQL. Обратите внимание, что GitLab 13.1 по-прежнему поддерживает только PostgreSQL 11, но поддержка PostgreSQL 12 планируется в будущем релизе.
  • Для повышения безопасности теперь вы можете передать ключ-секрет Kubernetes для значений заголовков с высокими требованиями к безопасности, таких как токен авторизации для конечных точек при настройке уведомлений реестра. За информацией о настройке обращайтесь к документации по настройкам реестра.

Документация по GitLab Chart.


Новая команда аварийного восстановления Geo для проверки перед аварийным переключением


(PREMIUM, ULTIMATE) Доступность


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


В GitLab 13.1 добавлена команда Geo gitlab-ctl promotion-preflight-checks, которая перечисляет все необходимые предполетные проверки и требует от системных администраторов подтверждения, что все эти проверки выполнены. Команда автоматически запускается при запуске
gitlab-ctl promote-to-primary-node.


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


Документация по аварийному переключению и оригинальный эпик.


Уменьшен размер индекса для расширенного глобального поиска


(STARTER, PREMIUM, ULTIMATE, BRONZE, SILVER, GOLD) Доступность


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


Мы отключили частичное совпадение при поиске по коду в GitLab 13.1, что привело к уменьшению размера индекса на 75%. Если вам нужно частичное совпадение, вы можете использовать подстановочные знаки в своем поисковом запросе. Частичное совпадение для других типов контента, таких как тикеты или мерж-реквесты, по-прежнему поддерживается.


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


Документация по интеграции поиска Elasticsearch и оригинальный тикет.


Используйте роли IAM для зашифрованных корзин Amazon S3


(CORE, STARTER, PREMIUM, ULTIMATE) Доступность


Теперь вы можете использовать роли AWS IAM для доступа к зашифрованным корзинам S3. Ранее такие корзины не работали вообще. Чтобы узнать больше, смотрите документацию по хранилищу объектов.


Документация по хранилищу объектов и оригинальный тикет.




Подробные release notes и инструкции по обновлению/установке можно прочитать в оригинальном англоязычном посте: GitLab 13.1 released with Alert Management and Code Quality Enhancements.


Над переводом с английского работали cattidourden, maryartkey, ainoneko и rishavant.

Подробнее..

Перевод Вышел релиз GitLab 13.7 с проверяющими для мерж-реквестов и автоматическим откатом при сбое

12.01.2021 16:20:24 | Автор: admin

Картинка для привлечения внимания


Ну и год же был 2020! Мы счастливы представить релиз 13.7 с более чем 45 фичами и улучшениями поставки ПО, вышедший как раз к праздникам.


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


Благодарим вас и всех членов команды GitLab, которые помогли сделать 2020 год невероятным, несмотря на невзгоды и непредсказуемые обстоятельства. Пожалуйста, оставайтесь в безопасности, будьте счастливы и здоровы в этот праздничный период.


Вот что вас ждёт в релизе 13.7:


Улучшенное управление проектами для развития совместной работы


Мерж-реквесты (в русской локализации GitLab запросы на слияние) имеют решающее значение для развития совместной работы и могут быть напрямую связаны с соответствующими тикетами, предоставляя центральное место для общения посредством комментариев, предложений по изменениям в коде и ревью кода. В этом релизе мы добавили проверяющих для мерж-реквестов способ улучшить процесс ревью кода, сделав его более лёгким и организованным. Теперь вы сможете быстро выяснить, кто участвовал в мерж-реквесте, или запросить у кого-то ревью, отправив соответствующее уведомление.


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


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


Улучшена автоматизация релизов и гибкость развёртывания


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


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


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


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


Более надёжное и эффективное управление пакетами и зависимостями


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


Мы также внесли улучшения в прокси зависимостей от GitLab; кстати, эта фича была перенесена в Core в GitLab 13.6.


Теперь вы можете вписаться в ограничения запросов Docker и ускорить работу конвейеров (в русской локализации GitLab сборочные линии) благодаря кэшированию образов контейнеров, размещённых на DockerHub, и быть уверенными в надёжности и эффективности работы с образами.


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


И, наконец, вы можете использовать предопределённые переменные с прокси зависимостей взамен того, чтобы полагаться на свои собственные определённые переменные или вшитые значения в вашем файле gitlab.ci-yml. Таким образом, появился более масштабируемый и эффективный способ начать проксирование и кэширование образов.


И это ещё не всё!


Взгляните на ещё несколько классных новых фич релиза 13.7:



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


6-7го января у нас прошёл виртуальный хакатон, узнайте больше об этом и будущих мероприятиях от GitLab здесь.


GitLab MVP badge


MVP этого месяца Rachel Gottesman


Rachel активно помогала нашей команде технических писателей внедрить согласованный стиль в документации для исправления использования будущего времени в наших документах. В релизе 13.7 Rachel открыла 33 мерж-реквеста, чем помогла нашей команде справиться с этой важной и кропотливой задачей. Спасибо, Rachel!


Основные фичи релиза GitLab 13.7


Проверяющие для мерж-реквестов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


Попросить коллегу просмотреть ваш код должно быть обычной частью рабочего процесса, но иногда это бывает неоправданно сложно. Такая простая задача, как запрос на ревью, может привести к путанице. Например, как именно следует запрашивать: через электронное письмо, комментарий, сообщение в чате? Без формального механизма ревью мерж-реквестов могут быть непоследовательными, и за их проведением будет сложно уследить. Раньше уже можно было назначить проверяющего на мерж-реквест, но и автор, и рецензент отображались в одном и том же поле Assignee, что не позволяло другим членам команды узнать, кто за что отвечал в этом мерж-реквесте.


GitLab 13.7 представляет новую фичу теперь авторы мерж-реквеста могут запросить ревью у конкретных пользователей. В новом поле Reviewers пользователи могут быть назначены проверяющими для мерж-реквеста аналогичным образом, как назначаются ответственные (assignee). Назначенные на ревью пользователи получат уведомление, предлагающее им просмотреть мерж-реквест. Таким образом, теперь существует формальный процесс запроса ревью для мерж-реквеста и уточняются роли каждого пользователя в работе над ним.


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


Reviewers for Merge Requests


Документация по назначению проверяющих для мерж-реквеста и оригинальный тикет.


Автоматический откат в случае сбоя


(ULTIMATE, GOLD) Стадия цикла DevOps: Release


Если у вас возникла критическая проблема с развёртыванием, ручные действия по её устранению могут занять довольно много времени и привести к сбоям на продакшене, что негативно скажется на пользователях. Теперь вы можете использовать автоматический механизм отката, который возвращает ваше развёртывание обратно к последнему успешному развёртыванию. Кроме того, когда GitLab находит проблемы на продакшене, он автоматически уведомляет вас об этом. Так вы всегда будете своевременно узнавать о проблемах, и получите драгоценное время для отладки, исследования и исправления проблем без лишних простоев в работе.



Документация по автоматическому откату при сбое и оригинальный тикет.


Клонирование тикета через быстрое действие


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Plan


Чтобы сделать создание похожих тикетов более эффективным, тикеты теперь поддерживают быстрое действие /clone, которое создаёт в том же проекте новый тикет с идентичными названием, описанием и метаданными. Быстрое действие /clone заменяет более трудоёмкий процесс, который включал в себя несколько шагов для создания тикета, копирования идентификатора или пути к исходному тикету и использование быстрого действия copy_meta.


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


Clone an issue with a quick action


Документация по быстрым действиям и оригинальный тикет.


Обработчик заданий GitLab для Red Hat OpenShift


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


Наконец-то стал доступен образ контейнера обработчика заданий GitLab (GitLab runner) для платформы контейнеров Red Hat OpenShift! Чтобы установить обработчик заданий на OpenShift, воспользуйтесь новым оператором обработчиков заданий GitLab. Он доступен на бета-канале в Red Hat's Operator Hub веб-консоли для администраторов кластеров OpenShift, уже развёрнутой по умолчанию на платформе, где они могут найти и выбрать операторы для установки на своём кластере. На платформе контейнеров OpenShift Operator Hub уже развёрнут по умолчанию. Мы планируем перенести оператор обработчика заданий GitLab на стабильный канал, а в начале 2021 года в общий доступ. Наконец, мы также разрабатываем оператор для GitLab, так что следите за будущими публикациями.


GitLab Runner for Red Hat OpenShift


Документация по установке на OpenShift и оригинальный тикет.


Просмотр статуса развёртываний на странице окружений


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


Ранее на странице окружений не было никакого способа узнать о том, что сейчас выполняется развёртывание. Теперь на этой странице отображаются статусы развёртываний и предупреждения, благодаря чему вы можете принять решение о том, какие действия нужно предпринять, основываясь на статусе развёртывания (успешное, неудачное или текущее). Например, можно остановить текущее развёртывание или откатить завершённое.


Show deployment status on the Environments page


Документация по работе с окружениями и оригинальный тикет.


Задавайте через пользовательский интерфейс процент трафика для канареечного развёртывания


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Release


В GitLab 13.7 вы можете менять процент трафика для канареечного развёртывания (значение canary-weight) непосредственно с досок развёртывания в пользовательском интерфейсе. Вы также можете менять это значение из gitlab-ci.yml и через API, но сделав это в пользовательском интерфейсе, вы сможете наблюдать за развёртыванием и при необходимости отмасштабировать поды прямо с досок развёртывания. Так у вас будет больше контроля над ручными или инкрементальными развёртываниями по таймеру, а также вы сможете лучше контролировать и даже снижать риски.


Set deployment traffic weight via the UI


Документация по заданию процента трафика для канареечного развёртывания и оригинальный тикет.


Просмотр частоты развёртываний через API


(ULTIMATE, GOLD) Стадия цикла DevOps: Release


В этом релизе в рамках первой итерации встроенной в GitLab поддержки метрик DORA4 была добавлена возможность узнавать частоту развёртываний на уровне проекта через API. Это позволяет отслеживать эффективность развёртывания с течением времени, легко находить узкие места и при необходимости быстро принимать меры по корректировке.


API support for deployment frequency


Документация по аналитике проектов и оригинальный тикет.


Поддержка нескольких файлов манифеста в проекте


(PREMIUM, ULTIMATE) Стадия цикла DevOps: Configure


В предыдущих релизах для использования нашего агента для Kubernetes (GitLab Kubernetes Agent) требовалось, чтобы пользователи собирали все ресурсы Kubernetes в один файл манифеста. Теперь же агент может собирать манифесты Kubernetes рекурсивно из указанных каталогов в вашем проекте. Ваши специалисты по платформе теперь смогут использовать один репозиторий для управления различными кластерами из единого места, а также описывать крупные развёртывания с помощью одного агента.


Support multiple manifest files in a project


Документация по настройке репозитория с агентом Kubernetes и оригинальный тикет.


Импорт требований из внешних инструментов


(ULTIMATE, GOLD) Стадия цикла DevOps: Plan


Для эффективной совместной работы очень важно, чтобы все ваши требования хранились в одном месте, поэтому мы рады сообщить, что теперь вы можете импортировать требования из CSV-файлов!


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


Import requirements from external tools


Документация по импорту требований из CSV-файла и оригинальный тикет.


Несколько конечных точек HTTP для оповещений


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Monitor


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


Integrate alerting tools with multiple HTTP endpoints


Документация по конечным точкам для оповещений и оригинальный эпик.


Синхронизация групп на GitLab.com с помощью SAML


(SILVER, GOLD) Стадия цикла DevOps: Manage


В GitLab 13.7 вы можете привязать группу в вашем поставщике учётных записей к группе на GitLab.com с помощью SAML. Членство в группе будет обновляться, когда пользователь войдёт в учётную запись GitLab через своего провайдера SAML. Эта фича снижает необходимость в ручном назначении групп, что снижает загрузку по группам для администраторов GitLab. Синхронизация групп также улучшает адаптацию новых членов групп, избавляя их от необходимости запрашивать доступ у администраторов групп GitLab.


SAML Group Sync for GitLab.com


Документация по синхронизации групп с помощью SAML и оригинальный эпик.


Другие улучшения в GitLab 13.7


DevOps Adoption


(ULTIMATE) Стадия цикла DevOps: Manage


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


  • Убедитесь, что вы получаете ожидаемую отдачу от использования GitLab.
  • Узнайте, какие группы отстают во внедрении GitLab, и помогайте им с настройкой DevOps.
  • Узнайте, какие группы используют определённые фичи, такие как конвейеры, и могут поделиться своим опытом с другими группами, которые хотят начать ими пользоваться.

DevOps Adoption


Документация по DevOps Adoption и оригинальный тикет.


Улучшенный пользовательский интерфейс для создания проектов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


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


Документация по созданию проектов и оригинальный тикет.


Ограничение создания проектов и групп для внешних аккаунтов


(PREMIUM, ULTIMATE, SILVER, GOLD) Стадия цикла DevOps: Manage


Для снижения риска случайного раскрытия интеллектуальной собственности администраторы GitLab теперь имеют больший контроль над аккаунтами, предоставляемыми через интеграцию группы с помощью SAML или SCIM. В первой итерации этой фичи администраторы могут запрещать своим пользователям создавать группы или проекты вне групп, к которым они принадлежат.


Документация по настройкам пользователя через SAML и оригинальный тикет.


Сортировка по числу блокируемых тикетов


(STARTER, PREMIUM, ULTIMATE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Plan


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


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


В версии 13.7 вы можете использовать фильтр Блокирует другие тикеты для списка тикетов, чтобы отсортировать его по числу блокируемых тикетов.


Sort issues by the number of issues they are blocking


Документация по сортировке и оригинальный тикет.


Просмотр файлов в мерж-реквестах по одному


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


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


В GitLab 13.7 мы добавили возможность просматривать файлы по одному при просмотре мерж-реквеста. При переходе на вкладку мерж-реквеста Изменения кликните на иконку с шестерёнками и поставьте галочку Показывать файлы по одному. После выбора этого параметра вы сможете просматривать файлы по одному, переключаясь между ними при помощи кнопок Предыдущий и Следующий.


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


Choose to show one file at a time directly from merge requests


Документация по ревью и управлению мерж-реквестами и оригинальный тикет.


Просмотр изменений мерж-реквеста в VS Code


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


При ревью мерж-реквестов в VS Code для обращения к изменениям зачастую приходится делать checkout ветки и затем пытаться разобраться в диффе между этой веткой и целевой веткой мержа.


С релизом 3.7.0 расширения GitLab Workflow изменения мерж-реквеста стали доступны напрямую в VS Code. Это позволяет быстро просматривать изменения в мерж-реквестах ваших проектов.


В рамках работы над добавлением полноценного ревью кода в VS Code следующим шагом мы собираемся добавить комментарии к диффам.


View Merge Request changes in VS Code


Документация по расширению для VS Code и оригинальный тикет.


Улучшенное скачивание артефактов для вложенных конвейеров


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


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


Теперь вы можете использовать новый синтаксис needs:pipeline, чтобы указать вложенному конвейеру, из какого конвейера ему нужно скачивать артефакты. Вы можете использовать его, чтобы скачивать артефакты из родительского конвейера или из другого вложенного конвейера в рамках той же иерархии.


Improved artifact downloads with child pipelines


Документация по скачиванию артефактов для вложенных конвейеров и оригинальный тикет.


Обход ограничений Docker и ускорение конвейеров


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package
Для более быстрых и надёжных сборок вы можете использовать нашу фичу, прокси зависимостей, для кэширования образов контейнеров из Docker Hub. Однако, когда Docker начал применять ограничения по количеству запросов docker pull, вы могли заметить, что даже когда ваш образ скачивался из кэша, Docker всё равно засчитывал его в лимит. Это происходило потому, что прокси зависимостей кэшировал только слои (или блоб-объекты) образа, но не манифест, который содержит информацию о том, как собрать данный образ. Так как манифест был необходим для сборки, всё равно приходилось выполнять pull. А если Docker Hub был недоступен, вы не могли скачать нужный образ.
Начиная с этого релиза прокси зависимостей будет кэшировать и слои, и манифест образа. Так что при первом скачивании с использованием alpine:latest образ будет добавлен в кэш прокси зависимостей, и это будет считаться за один pull. В следующий раз, когда вы будете скачивать alpine:latest, всё будет скачиваться из кэша, даже если Docker Hub недоступен, и это скачивание не будет учитываться в лимите Docker.


Напоминаем вам, что начиная с 13.6 прокси зависимостей стал доступен в плане Core. Поэтому попробуйте эту фичу сейчас и скажите нам, что вы о ней думаете. Или даже лучше, помогите нам с открытыми тикетами.



Документация по прокси зависимостей и оригинальный тикет.


Быстрый поиск и просмотр общих пакетов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package


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


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



Документация по просмотру пакетов и оригинальный тикет.


Прокси зависимостей для приватных проектов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package


Вы можете использовать прокси зависимостей GitLab для проксирования и кэширования образов контейнеров из Docker Hub. До последнего времени эта фича была доступна только для публичных групп, что не позволяло многим пользователям её использовать.


Теперь вы можете использовать прокси зависимостей и для приватных проектов. Вы можете снизить свои скачивания с Docker Hub путём кэширования ваших образов контейнера для использования их в будущем. Так как прокси зависимостей хранит образы Docker в пространстве, связанном с вашей группой, вы должны авторизоваться с вашим логином и паролем GitLab или с личным токеном доступа, для которого есть разрешение как минимум на чтение (read_registry).


Документация по прокси зависимостей и оригинальный тикет.


Улучшенная поддержка анализаторов SAST для нескольких проектов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Secure


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


Документация по поддержке репозиториев для нескольких проектов и оригинальный эпик.


Описание релиза во внешнем файле


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


Если вы создаёте релизы в конвейерах через файл .gitlab-ci.yml вашего проекта, вам, возможно, было сложно поддерживать в актуальном состоянии описание каждого релиза. В релизе GitLab 13.7 вы можете задавать описание вашего релиза в файле с контролем версий или в автоматически генерируемом файле и вызывать его из .gitlab-ci.yml. При этом содержимое файла загружается в описание релиза в формате Markdown. Это упрощает создание, поддержку и использование контроля версий для релизов, а также будет особенно полезно при автогенерации лога изменений. Огромное спасибо Nejc Habjan и Siemens за этот невероятный вклад!



Документация по описаниям релизов и оригинальный тикет.


Поддержка для версий Kubernetes 1.17, 1.18 и 1.19


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Configure


Поддержка GitLab для последних версий Kubernetes позволяет вам пользоваться преимуществами интеграций GitLab с Kubernetes, такими как GitLab Kubernetes Agent, Auto DevOps и на более поздних кластерах GitLab Managed Apps. В этом релизе GitLab добавил официальную поддержку для версий Kubernetes 1.17, 1.18 и 1.19.


Документация по кластерам и оригинальный тикет.


Geo поддерживает репликацию сниппетов


(PREMIUM, ULTIMATE) Доступность


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


В данный момент мы не поддерживаем верификацию для этого типа данных, но мы планируем добавить её в будущем.


Документация по репликации Geo и оригинальный эпик.


Поддержка зашифрованных учётных данных LDAP


(CORE, STARTER, PREMIUM, ULTIMATE) Доступность


GitLab использует единый файл конфигурации, например gitlab.rb в Omnibus GitLab, что упрощает настройку всех связанных сервисов. В этот файл конфигурации включены некоторые секретные ключи, например учётные данные для аутентификации на сервере LDAP. Хотя для доступа к этому файлу требуются специальные права, хорошей практикой считается отделять секретные ключи от конфигурации.


Установки Omnibus GitLab и Source теперь поддерживают зашифрованные учётные данные, причём первыми поддерживаемыми учётными данными стали LDAP. Это снижает уязвимость конфигурационного файла GitLab, а также помогает достичь соответствия требованиям заказчика.


Документация по настройке зашифрованных учётных данных LDAP и оригинальный тикет.


Веб-хуки при добавлении новых участников группы


(STARTER, PREMIUM, ULTIMATE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


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


Документация по веб-хукам и оригинальный тикет.


Улучшенная фильтрация и сортировка списков участников группы


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Manage


Мы продолжили улучшать наш список участников группы и добавили для него новые возможности фильтрации и сортировки. Это поможет администраторам группы быстро находить нужную им информацию. Например, сортировку по последнему времени входа (Last sign-in) можно использовать для поиска пользователей, которые в последнее время не заходили на GitLab, и для помощи в управлении лицензиями.


Improved group members list filtering and sorting


Документация по фильтрации и сортировке участников группы и оригинальный тикет.


Автоматическая подготовка профиля пользователя с SAML


(SILVER, GOLD) Стадия цикла DevOps: Manage


Раньше в качестве одной из частей включения в группу с SAML пользователям нужно было заполнять форму регистрации. В GitLab 13.7 мы представляем синхронизацию пользователей для групп с использованием SAML. Когда пользователь в первый раз входит в группу с SAML, учётная запись пользователя создаётся для него автоматически, если нет существующего пользователя с таким же адресом электронной почты. Автоматическая подготовка с SAML улучшает процесс адаптации новых пользователей и гарантирует, что вновь созданные учётные записи содержат правильную информацию.


Документация по настройке групп с SAML и оригинальный тикет.


Настраиваемый адрес электронной почты для службы поддержки


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Plan


Раньше вашим пользователям было трудно запомнить (а следовательно, и использовать) адрес электронной почты службы поддержки GitLab. С введением настраиваемого адреса электронной почты теперь можно выбрать суффикс адреса, который имеет смысл для вашей компании и который будет легче запомнить вашим пользователям. Это ещё один шаг, который нужен для того, чтобы вы могли предоставлять своим пользователям качественную поддержку.


Документация по настройке адреса электронной почты для службы поддержки и оригинальный тикет.


Различайте изменения форматирования и правки, сделанные из редактора статических сайтов


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Create


Редактор статических сайтов предлагает интуитивно понятный и знакомый всем режим редактирования WYSIWYG для контента Markdown. Чтобы обеспечить единообразный формат вывода Markdown, редактор WYSIWYG автоматически переформатирует содержимое страницы в соответствии с соглашениями о стилях, определёнными в парсере Markdown. Это происходит полностью в фоновом режиме ещё до того, как вы начнёте редактировать. Однако эти изменения форматирования коммитятся вместе с вашими изменениями содержимого. Если страница, которую вы редактируете, не следовала тем же соглашениям о стилях, для проверяющих итогового мерж-реквеста может быть сложно отличить ваши изменения от автоматического форматирования.


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


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


Документация по редактору статических сайтов и оригинальный тикет.


Предзаполненные переменные при ручном запуске конвейеров


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Verify


Раньше, когда вы хотели запустить конвейер вручную, вам нужно было узнать нужные переменные, а затем ввести их на странице Запуск конвейера (Run Pipeline). Это может быть утомительно и чревато ошибками, если нужно ввести множество пар ключ-значение. Теперь форма для запуска конвейера будет сгенерирована для вашего конвейера с переменными, предварительно заполненными на основе определений переменных в вашем файле .gitlab-ci.yml, что сделает этот процесс более эффективным.


Pre-filled variables when running pipelines manually


Документация по ручному запуску конвейера и оригинальный тикет.


Собранные с помощью CI/CD пакеты всегда отображают информацию о сборке


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package


Если вы публиковали пакеты в реестре пакетов, то могли заметить, что пакеты, созданные с помощью GitLab CI/CD, не всегда отображали коммит и конвейер, ответственные за создание или обновление вашего пакета. Это могло происходить по нескольким причинам.


Во-первых, возможно, мы ещё не поддерживали эту функцию, как в случае с Composer и Conan. Во-вторых, проблема возникала у тех из вас, кто обновлял одну и ту же версию пакета из разных веток или коммитов. Однако до недавнего времени пользовательский интерфейс отображал только первое развёртывание без каких-либо обновлений. Кроме того, на странице подробных сведений отображается ветка, в которой был создан пакет, а не самый последний коммит. В результате вам приходилось искать эту информацию, просматривая историю коммитов, что было не очень эффективно.


В дальнейшем любой пакет, собранный или обновлённый с помощью GitLab CI/CD, будет отображать информацию о коммите и конвейере в пользовательском интерфейсе пакетов. Чтобы избежать проблем с производительностью или пользовательским интерфейсом, будут отображаться только пять обновлений пакета. В майлстоуне 13.8 мы создадим дизайн, который поможет вам легко просматривать все данные, включая историю. А пока вы можете использовать API пакетов, чтобы смотреть всю историю сборки данного пакета.


Packages built with CI/CD always display build info


Документация по реестру пакетов и сборке пакетов с помощью GitLab CI/CD и оригинальный тикет.


Используйте предопределённые переменные с прокси зависимостей


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Package


С помощью проксирования и кэширования образов контейнеров из Docker Hub прокси зависимостей помогает вам повысить производительность ваших конвейеров. Несмотря на то, что прокси-сервер предназначен для интенсивного использования с CI/CD, для использования этой фичи вам нужно было определить свои собственные переменные или прописать значения в вашем файле gitlab.ci-yml. Это затрудняло начало работы для тех, кто работает один, и не позволяло использовать его в качестве масштабируемого решения, особенно для организаций с множеством различных групп и проектов.


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


  • CI_DEPENDENCY_PROXY_USER: пользователь CI для входа в прокси зависимостей,
  • CI_DEPENDENCY_PROXY_PASSWORD: пароль для входа в прокси зависимостей,
  • CI_DEPENDENCY_PROXY_SERVER: сервер для входа в прокси зависимостей,
  • CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX: префикс образа для извлечения образов через прокси зависимостей.

Попробуйте и дайте нам знать, что вы думаете!


Документация по аутентификации в прокси зависимостей с помощью CI/CD и оригинальный тикет.


Результаты сканирований безопасности в виджете мерж-реквеста стали удобнее


(CORE, STARTER, PREMIUM, FREE, BRONZE, SILVER) Стадия цикла DevOps: Secure


С помощью SAST и поиска секретных ключей, которые теперь доступны для всех пользователей, мы упростили жизнь всем пользователям GitLab, взаимодействующим с результатами сканирования безопасности в мерж-реквесте, за счёт облегчения доступа к результатам сканирования безопасности. Ранее результаты сканирования безопасности были доступны только на странице Обзор конвейера, и вы должны были знать, где искать, чтобы найти их там. Теперь все мерж-реквесты будут показывать, были ли для них запущены проверки безопасности, и помогут вам найти артефакты задания. Это изменение не затрагивает работу с мерж-реквестами для пользователей плана Ultimate.


Improved MR experience for security scans


Документация по просмотру результатов сканирования безопасности в мерж-реквесте и оригинальный эпик.


Специальные ссылки на уязвимости


(ULTIMATE, GOLD) Стадия цикла DevOps: Secure


Мы ввели уязвимости как полноценные объекты в 12.10. Будучи объектом, каждая из них имеет уникальный URL-адрес, позволяющий напрямую перейти к деталям любой уязвимости. Несмотря на значительное улучшение видимости и согласованности, ссылки на уязвимости в тикетах и эпиках (в русской локализации GitLab цели) всё равно нужно копировать вручную в виде ссылок Markdown. Это делает неэффективным совместное использование, а ссылки на уязвимости в других областях GitLab более громоздкими, чем для других объектов, например тикетов.


Теперь на уязвимости можно ссылаться с помощью специальных ссылок. На них впервые будет опробован новый синтаксис [object_type:ID], который в конечном итоге распространится на другие существующие ссылки. Теперь вы можете быстро вставить ссылку на уязвимость из любого места, где обычно используется специальная ссылка, например из описания тикета или мерж-реквеста. Просто введите [vulnerability:123] в описании тикета, чтобы вставить ссылку на уязвимость с идентификатором 123 в том же проекте. Вы также можете добавить к идентификатору префикс пространства имён или проекта, чтобы ссылаться на уязвимости вне контекста текущего проекта.


Документация по специальным ссылкам и оригинальный тикет.


Смотрите, какие коммиты и конвейеры выполняются в форке, а какие в родительском проекте


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Стадия цикла DevOps: Release


После того, как мы решили проблему, описанную в тикете 217451 в GitLab 13.3, вы получили возможность разрешать разработчикам родительского проекта создавать конвейеры для мерж-реквестов в форках. Однако не было никакого способа узнать контекст, в котором был запущен конвейер.


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


See which commits and pipelines run in the fork project vs. the parent project


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


Запросы к базе данных выполняются быстрее при использовании балансировщика нагрузки


(CORE, STARTER, PREMIUM, ULTIMATE, FREE, BRONZE, SILVER, GOLD) Доступность


Многие запросы к базе данных повторяются несколько раз, так что их можно кэшировать для повышения общей производительности. Для GitLab можно кэшировать примерно 10% всех запросов. В GitLab 13.7 мы включили кэширование запросов к базе данных, когда используется балансировка нагрузки базы данных. На GitLab.com это приводит к кэшированию ~700 000 запросов каждую минуту и сокращает среднее время выполнения запросов вплоть до 10%.


Для запросов, которые выполняются более 100 раз, мы уменьшили продолжительность запроса на 11-31% и кэшировали ~30% всех операторов SELECT, которые бы в противном случае выполнялись на реплике базы данных.


Документация по балансировке нагрузки на базу данных и оригинальный тикет.


Для новых установок по умолчанию используется PostgreSQL 12


(CORE, STARTER, PREMIUM, ULTIMATE) Доступность


Начиная с GitLab 13.3 PostgreSQL 12 был доступен в качестве опции как для пакетов Omnibus, так и для нашего Helm chart. PostgreSQL 12 улучшает производительность, а также предлагает значительные преимущества при индексировании и секционировании.


Начиная с GitLab 13.7 новые установки GitLab будут по умолчанию использовать PostgreSQL 12. Чтобы выполнить обновление вручную, запустите gitlab-ctl pg-upgrade.


Многонодовые инстансы базы данных должны будут переключиться с repmgr на Patroni до обновления с помощью Patroni. Затем можно обновить и повторно синхронизировать вторичные ноды Geo.


Документация по настройкам баз данных в GitLab 13.3 и более поздних версиях и оригинальный тикет.




Полный текст релиза и инструкции по обновлению/установке вы можете найти в оригинальном англоязычном посте: GitLab 13.7 released with merge request reviewers and automatic rollback upon failure.


Над переводом с английского работали cattidourden, maryartkey, ainoneko и rishavant.

Подробнее..

Автоматизация ручных действий с GitHub Actions

12.01.2021 18:23:11 | Автор: admin

GitHub Actions инструмент для автоматизации рутинных действий с вашего пакета на GitHub.

Из личного опыта расскажу, как без опыта и знаний о настройке CI, я научился автоматизировать рутину в своем Open Source проекте всего за день и что на самом деле это действительно не так страшно и сложно, как многие думают.

GitHub предоставляет действительно удобные и рабочие инструменты для этого.

План действий

  • настроим CI в GitHub Actions для небольшого проекта на PHP

  • научимся запускать тесты в матрице с покрытием (зачем это нужно также расскажу)

  • создадим ботов, которые будут назначать ревьюющих / исполнителей, выставлять метки для PR-s (на основе измененных файлов), а по окончании ревью и проверок в Check Suite будут автоматом мержить наши PR, а сами ветки будут удаляться автоматически.

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

В общем, мы постараемся минимизировать ручной труд так, чтобы от вас, как от автора вашего Open-Source пакета, оставалось только писать код, ревьюить и апрувить пулл-реквесты, а все остальное за вас делали боты. А если вы умеете делегировать, то и ревью и написание кода можно также возложить на плечи ваших соратников, проект будет и развиваться без вашего участия.

Настройка CI

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

Создайте файл примерно с таким содержимым:

.github/workflows/ci.yml
name: CIon:  push:    branches:      - master  pull_request:    types:      - opened      - reopened      - edited      - synchronizeenv:  COVERAGE: '1'  php_extensions: 'pdo, pdo_pgsql, pcntl, pcov, ...'  key: cache-v0.1  DB_USER: 'postgres'  DB_NAME: 'testing'  DB_PASSWORD: 'postgres'  DB_HOST: '127.0.0.1'jobs:  lint:    runs-on: '${{ matrix.operating_system }}'    timeout-minutes: 20    strategy:      matrix:        operating_system: ['ubuntu-latest']        php_versions: ['7.4']      fail-fast: false    env:      PHP_CS_FIXER_FUTURE_MODE: '0'    name: 'Lint PHP'    steps:      - name: 'Checkout'        uses: actions/checkout@v2      - name: 'Setup cache environment'        id: cache-env        uses: shivammathur/cache-extensions@v1        with:          php-version: '${{ matrix.php_versions }}'          extensions: '${{ env.php_extensions }}'          key: '${{ env.key }}'      - name: 'Cache extensions'        uses: actions/cache@v1        with:          path: '${{ steps.cache-env.outputs.dir }}'          key: '${{ steps.cache-env.outputs.key }}'          restore-keys: '${{ steps.cache-env.outputs.key }}'      - name: 'Setup PHP'        uses: shivammathur/setup-php@v2        with:          php-version: ${{ matrix.php_versions }}          extensions: '${{ env.php_extensions }}'          ini-values: memory_limit=-1          tools: pecl, composer          coverage: none      - name: 'Setup problem matchers for PHP (aka PHP error logs)'        run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"'      - name: 'Setup problem matchers for PHPUnit'        run: 'echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"'      - name: 'Install PHP dependencies with Composer'        run: composer install --prefer-dist --no-progress --no-suggest --optimize-autoloader        working-directory: './'      - name: 'Linting PHP source files'        run: 'composer lint'  test:    strategy:      fail-fast: false      matrix:        operating_system: ['ubuntu-latest']        postgres: [11, 12]        php_versions: ['7.3', '7.4', '8.0']        experimental: false        include:          - operating_system: ubuntu-latest            postgres: '13'            php_versions: '8.0'            experimental: true       runs-on: '${{ matrix.operating_system }}'    services:      postgres:        image: 'postgres:${{ matrix.postgres }}'        env:          POSTGRES_USER: ${{ env.DB_USER }}          POSTGRES_PASSWORD: ${{ env.DB_PASSWORD }}          POSTGRES_DB: ${{ env.DB_NAME }}        ports:          - 5432:5432        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5    name: 'Test / PHP ${{ matrix.php_versions }} / Postgres ${{ matrix.postgres }}'    needs:      - lint    steps:      - name: 'Checkout'        uses: actions/checkout@v2        with:          fetch-depth: 1      - name: 'Install postgres client'        run: |          sudo apt-get update -y          sudo apt-get install -y libpq-dev postgresql-client      - name: 'Setup cache environment'        id: cache-env        uses: shivammathur/cache-extensions@v1        with:          php-version: ${{ matrix.php_versions }}          extensions: ${{ env.php_extensions }}          key: '${{ env.key }}'      - name: 'Cache extensions'        uses: actions/cache@v1        with:          path: '${{ steps.cache-env.outputs.dir }}'          key: '${{ steps.cache-env.outputs.key }}'          restore-keys: '${{ steps.cache-env.outputs.key }}'      - name: 'Setup PHP'        uses: shivammathur/setup-php@v2        with:          php-version: ${{ matrix.php_versions }}          extensions: ${{ env.php_extensions }}          ini-values: 'pcov.directory=src, date.timezone=UTC, upload_max_filesize=20M, post_max_size=20M, memory_limit=512M, short_open_tag=Off'          coverage: pcov          tools: 'phpunit'      - name: 'Install PHP dependencies with Composer'        run: composer install --prefer-dist --no-progress --no-suggest --optimize-autoloader        working-directory: './'      - name: 'Run Unit Tests with PHPUnit'        continue-on-error: ${{ matrix.experimental }}        run: |          sed -e "s/\${USERNAME}/${{ env.DB_USER }}/" \              -e "s/\${PASSWORD}/${{ env.DB_PASSWORD }}/" \              -e "s/\${DATABASE}/${{ env.DB_NAME }}/" \              -e "s/\${HOST}/${{ env.DB_HOST }}/" \              phpunit.xml.dist > phpunit.xml          ./vendor/bin/phpunit \            --verbose \            --stderr \            --coverage-clover build/logs/clover.xml        working-directory: './'      - name: 'Upload coverage results to Coveralls'        if: ${{ !matrix.experimental }}        env:          COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}          COVERALLS_PARALLEL: true          COVERALLS_FLAG_NAME: php-${{ matrix.php_versions }}-postgres-${{ matrix.postgres }}        run: |          ./vendor/bin/php-coveralls \            --coverage_clover=build/logs/clover.xml \            -v  coverage:    needs: test    runs-on: ubuntu-latest    name: "Code coverage"    steps:      - name: 'Coveralls Finished'        uses: coverallsapp/github-action@v1.1.2        with:          github-token: ${{ secrets.GITHUB_TOKEN }}          parallel-finished: true

Расскажу лишь в кратце, в этом конфиге 3 основных шага (lint, tests и coverage)

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

Если код не соответствует code style проекта, джобка падает и CI дальше не запускается. В данном примере, я использую линтер с правилами от umbrellio/code-style-php, а сами скрипты запуска описаны так (первый для проверки, второй для авто фиксов для локального использования):

"scripts": {   "lint": "ecs check --config=ecs.yml .",   "lint-fix": "ecs check --config=ecs.yml . --fix"}

test - тестируем наше приложение в матрице следующего ПО (os, postgres и php), а через опцию include добавляем что-то дополнительное (важно сохранить структуру ключей матрицы).

В целом тут тоже ничего нет сложного, разве что два момента:

  • опция experimental (к слову назвать опцию можно как угодно) для матрицы нужна для того, чтобы падающие джобки в экспериментальном окружении не фейлили CI, например, когда вы добавляете поддержку новой версии PHP, и не ставите самоцелью решать упавшие тесты или покрытие прям щас. Такие джобки игнорируются (если падают).

  • строки с sed -e "s/\${USERNAME}/${{ env.DB_USER }}/"... нужны для того, чтобы переменные подключения к БД были записаны из файла phpunit.xml.dist с плейсхолдерами в phpunit.xml, это не панацея, вы можете использовать переменные окружения ENV, но на всякий случай файл доступен тут:

phpunit.xml.dist
<?xml version="1.0" encoding="UTF-8"?><phpunit xmlns:xsi="http://personeltest.ru/away/www.w3.org/2001/XMLSchema-instance"         bootstrap="vendor/autoload.php"         colors="true"         convertErrorsToExceptions="true"         convertNoticesToExceptions="true"         convertWarningsToExceptions="true"         processIsolation="false"         stopOnFailure="false"         xsi:noNamespaceSchemaLocation="http://personeltest.ru/aways/schema.phpunit.de/9.3/phpunit.xsd">    <php>        <env name="APP_ENV" value="testing"/>        <ini name="error_reporting" value="-1" />        <var name="db_type" value="pdo_pgsql"/>        <var name="db_host" value="${HOST}" />        <var name="db_username" value="${USERNAME}" />        <var name="db_password" value="${PASSWORD}" />        <var name="db_database" value="${DATABASE}" />        <var name="db_port" value="5432"/>    </php>    <filter>        <whitelist processUncoveredFilesFromWhitelist="true">            <directory suffix=".php">./src</directory>            <exclude>                <file>./src/.meta.php</file>            </exclude>        </whitelist>    </filter>    <testsuites>        <testsuite name="Test suite">            <directory suffix="Test.php">./tests</directory>        </testsuite>    </testsuites></phpunit>

coverage - т.к. тестирование и покрытие также происходит в матрице, т.к. часть кода может быть написана под одну версию Postgres, а другая под другую и оформлено в виде условий в вашем коде, то покрыть на 100% за одну итерацию может быть невозможно. К сожалению, composer, в отличие от Bandler-а от Ruby, так делать не умеет.

Но т.к. я перфекционист и мне нужен badge:100% coverage, в моем случае используется матрица покрытия и затем, отправленные отчеты о покрытии, мержатся в один. Например, coveralls.io поддерживает обьединенный кавераж.

Теперь когда у нас есть CI, мы попробуем подключить ботов для автоматизации нашей рутины.

Авто-назначение меток (labels)

Для подключения бота создайте два файла (конфиг и скрипт):

.github/labeler.config.yml
type:build:  - ".github/**/*"  - ".coveralls.yml"  - ".gitignore"  - "ecs.yml"  - "phpcs.xml"dependencies:  - "composer.json"  - "composer.lock"type:common  - "src/**/*"type:tests:  - 'tests/**/*'  - 'phpunit.xml.dist'  - 'tests.sh'theme:docs:  - "README.md"  - "LICENSE"  - "CONTRIBUTING.md"  - "CODE_OF_CONDUCT.md"

Тут по сути мы описываем маппинг меток к файлам и директориям вашего пакета, в зависимости от того, какие файлы будут изменены в рамках вашего PR, такие метки будут автоматически выставлены к PR.

Метки нужны для того, чтобы в последствии мы могли на их основании генерировать Summary для наших релизов и определять степень важности PR (будет ли это patch, minor или major). Вообще говоря, метки помогают визуально категоризировать пулл-реквесты, что очень удобно, когда их (pull-реквестов) много.

.github/workflows/labeler.yml
name: "Auto labeling for a pull request"on:  - pull_request_targetjobs:  triage:    name: "Checking for labels"    runs-on: ubuntu-latest    steps:      - uses: actions/labeler@main        with:          repo-token: "${{ secrets.GITHUB_TOKEN }}"          sync-labels: true          configuration-path: ".github/labeler.config.yml"

Авто-назначение ревьюеров и исполнителей

Для подключения бота создайте два файла (конфиг и скрипт):

.github/assignee.config.yml
addReviewers: truenumberOfReviewers: 1reviewers: - pvsaitpeaddAssignees: trueassignees: - pvsaintpenumberOfAssignees: 1skipKeywords:  - wip  - draft

Тут мы по сути описываем, кто и в каком кол-ве будет назначаться в качестве ревьюеров, и просто перечисляем логины пользователей с GitHub.

.github/workflows/assignee.yml
name: 'Auto assign assignees or reviewers'on: pull_requestjobs:  add-reviews:    name: "Auto assignment of a assignee"    runs-on: ubuntu-latest    steps:      - uses: kentaro-m/auto-assign-action@v1.1.2        with:          configuration-path: ".github/assignee.config.yml"

Авто-мержирование проверенных PR

Для подключения бота создайте файл скрипта с содержимым:

.github/workflows/auto_merge.yml
name: 'Auto merge of approved pull requests with passed checks'on:  pull_request:    types:      - labeled      - unlabeled      - synchronize      - opened      - edited      - ready_for_review      - reopened      - unlocked  pull_request_review:    types:      - submitted  check_suite:    types:      - completed  status: {}jobs:  automerge:    runs-on: ubuntu-latest    steps:      - name: 'Automerge PR'        uses: "pascalgn/automerge-action@v0.12.0"        env:          GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"          MERGE_METHOD: 'squash'          MERGE_LABELS: "approved,!work in progress"          MERGE_REMOVE_LABELS: "approved"          MERGE_COMMIT_MESSAGE: "pull-request-description"          MERGE_RETRIES: "6"          MERGE_RETRY_SLEEP: "10000"          UPDATE_LABELS: ""          UPDATE_METHOD: "rebase"          MERGE_DELETE_BRANCH: false

Из важного тут только то, что мержится будут только те PR, у которых будет выставлена метка approved, а также если все проверки в CheckSuite будут пройдены.

Мержить будем через Squash, чтобы была красивая история коммитов.

Авто-апрув отревьюенных PR

Когда ревьюющий ставит аппрув в PR, будем автоматом проставлять метку approved, создайте файл скрипта с содержимым:

.github/workflows/auto_approve.yml
on: pull_request_reviewname: 'Label approved pull requests'jobs:  labelWhenApproved:    name: 'Label when approved'    runs-on: ubuntu-latest    steps:      - name: 'Label when approved'        uses: pullreminders/label-when-approved-action@master        env:          APPROVALS: "1"          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}          ADD_LABEL: "approved"          REMOVE_LABEL: "awaiting review"

Авто-выпуск релизов с ченджлогом

Для подключения бота создайте два файла (конфиг и скрипт) с содержимым:

.github/release-drafter.yml
template: |  ## Changes  $CHANGESchange-template: '- **$TITLE** (#$NUMBER)'version-template: "$MAJOR.$MINOR.$PATCH"name-template: '$RESOLVED_VERSION'tag-template: '$RESOLVED_VERSION'categories:  - title: 'Features'    labels:      - 'feature'      - 'type:common'  - title: 'Bug Fixes'    labels:      - 'fix'      - 'bugfix'      - 'bug'      - 'hotfix'      - 'dependencies'  - title: 'Maintenance'    labels:      - 'type:build'      - 'refactoring'      - 'theme:docs'      - 'type:tests'change-title-escapes: '\<*_&'version-resolver:  major:    labels:      - major      - refactoring  minor:    labels:      - feature      - minor      - type:common  patch:    labels:      - patch      - type:build      - bug      - bugfix      - hotfix      - fix      - theme:docs      - type:tests  default: patch

В зависимости от меток, бот будет увеличивать либо MAJOR, либо MINOR, либо версию PATCH

.github/workflows/release_drafter.yml
name: Release Drafteron:  push:    branches:      - masterjobs:  update_release_draft:    runs-on: ubuntu-latest    steps:      - uses: release-drafter/release-drafter@v5        with:          publish: true        env:          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Теперь нужно провести некоторые настройки в GitHub Settings вашего проекта

Настройка Check Suite в GitHub

По умолчанию ветки в GitHub никак не ограничены, и пушить в них может каждый, кто имеет доступ на запись, но если вы хотите, чтобы код был красивый, чтобы код был покрыт на 100%, и у вас есть прочие хотелки, необходимо поставить ограничения и настроить Check Suite.

Пример, где настраиваются ограничения веток

Выберите основную ветку и создайте правило. Из того, на что следует обратить внимание, это следующие моменты:

Настройка approvals

По сути, тут мы настраиваем кол-во людей, которые должны посмотреть PR, будут ли сбрасываться апрувы, после появления новых коммитов, а также необходимо ли участие Code Owners в ревью.

Пример, как настраиваются approvalls

Настройка обязательных проверок для Check Suite

Все наши проверки (в CI это джобки, в основном, но и другие интеграции тоже, например, Coveralls / Scrutinizer, и прочие анализаторы кода), могут быть как обязательными или необязательными.

Если проверка обязательная, то мержирование PR будет заблокировано пока все проверки не будут пройдены.

Пример, как настроить Check Suite для ветки

Автоматически удаляем ветки после мержа

Чтобы у нас была красивая история коммитов, а также чтобы не удалять вручную ветки после мержа, в Settings => Options нужно разрешить только Squash, если вы хотите красивую историю коммитов и включить опцию "Automatically delete head branches"

Пример настройки тут

Настройка веб-хука для packagist.org

Тут все стандартно, на сайте packagist есть инструкция, но для полноты поста выложу тоже.

Пример, как настроить webhook packagist

Секретный ключ можно взять на packagist в настройках вашего профиля (Show Api Token).

Таким образом, если вы поддерживаете достаточное кол-во OpenSource проектов, и в каждом из них есть некоторое количество активных Contributor-ов (с правами записи), вы можете настроить CI так, что сообщество будет само писать код, а ваши доверенные лица будут ревьюить, общий workflow будет соблюден.

Вы даже можете в coveralls / scrutinizer настроить правила, чтобы Check Suite падал если % покрытия кода меньше 100%, а в Readme напичкать баджиками для красоты, например так:

Буду рад, если мой туториал будет кому-то полезен, т.к. перед написанием данного поста я впервые столкнулся с GitHub Actions, я не DevOps и настройкой CI не занимаюсь, самому пришлось прогуглить не один сайт, чтобы настроить такой workflow, который был нужен мне.

Подробнее..

Ваш безлимит как увеличить пропускную способность автомерджа

21.06.2021 14:12:41 | Автор: admin

Отыщи всему начало, и ты многое поймёшь (Козьма Прутков).

Меня зовут Руслан, я релиз-инженер в Badoo и Bumble. Недавно я столкнулся с необходимостью оптимизировать механизм автомерджа в мобильных проектах. Задача оказалась интересной, поэтому я решил поделиться её решением с вами. В статье я расскажу, как у нас раньше было реализовано автоматическое слияние веток Git и как потом мы увеличили пропускную способность автомерджа и сохранили надёжность процессов на прежнем высоком уровне.

Свой автомердж

Многие программисты ежедневно запускают git merge, разрешают конфликты и проверяют свои действия тестами. Кто-то автоматизирует сборки, чтобы они запускались автоматически на отдельном сервере. Но решать, какие ветки сливать, всё равно приходится человеку. Кто-то идёт дальше и добавляет автоматическое слияние изменений, получая систему непрерывной интеграции (Continuous Integration, или CI).

Например, GitHub предлагает полуручной режим, при котором пользователь с правом делать записи в репозиторий может поставить флажок Allow auto-merge (Разрешить автомердж). При соблюдении условий, заданных в настройках, ветка будет соединена с целевой веткой. Bitbucket поддерживает большую степень автоматизации, накладывая при этом существенные ограничения на модель ветвления, имена веток и на количество мерджей.

Такой автоматизации может быть достаточно для небольших проектов. Но с увеличением количества разработчиков и веток, ограничения, накладываемые сервисами, могут существенно повлиять на производительность CI. Например, раньше у нас была система мерджа, при которой основная ветка всегда находилась в стабильном состоянии благодаря последовательной стратегии слияний. Обязательным условием слияния была успешная сборка при наличии всех коммитов основной ветки в ветке разработчика. Работает эта стратегия надёжно, но у неё есть предел, определяемый временем сборки. И этого предела оказалось недостаточно. При времени сборки в 30 минут на обработку 100 слияний в день потребовалось бы более двух суток. Чтобы исключить ограничения подобного рода и получить максимальную свободу выбора стратегий мерджа и моделей ветвления, мы создали собственный автомердж.

Итак, у нас есть свой автомердж, который мы адаптируем под нужды каждой команды. Давайте рассмотрим реализацию одной из наиболее интересных схем, которую используют наши команды Android и iOS.

Термины

Main. Так я буду ссылаться на основную ветку репозитория Git. И коротко, и безопасно. =)

Сборка. Под этим будем иметь в виду сборку в TeamCity, ассоциированную с веткой Git и тикетом в трекере Jira. В ней выполняются как минимум статический анализ, компиляция и тестирование. Удачная сборка на последней ревизии ветки в сочетании со статусом тикета To Merge это однo из необходимых условий автомерджа.

Пример модели ветвления

Испробовав разные модели ветвления в мобильных проектах, мы пришли к следующему упрощённому варианту:

На основе ветки main разработчик создаёт ветку с названием, включающим идентификатор тикета в трекере, например PRJ-k. По завершении работы над тикетом разработчик переводит его в статус Resolved. При помощи хуков, встроенных в трекер, мы запускаем для ветки тикета сборку. В определённый момент, когда изменения прошли ревью и необходимые проверки автотестами на разных уровнях, тикет получает статус To Merge, его забирает автоматика и отправляет в main.

Раз в неделю на основе main мы создаём ветку релиза release_x.y.z, запускаем на ней финальные сборки, при необходимости исправляем ошибки и наконец выкладываем результат сборки релиза в App Store или Google Play. Все фазы веток отражаются в статусах и дополнительных полях тикетов Jira. В общении с Jira помогает наш клиент REST API.

Такая простая модель не только позволила нам построить надёжный автомердж, но и оказалась удобной для всех участников процесса. Однако сама реализация автомерджа менялась несколько раз, прежде чем мы добились высокой производительности и минимизировали количество побочных эффектов: конфликтов, переоткрытий тикетов и ненужных пересборок.

Первая версия: жадная стратегия

Сначала мы шли от простого и очевидного. Брали все тикеты, находящиеся в статусе To Merge, выбирали из них те, для которых есть успешные сборки, и отправляли их в main командой git merge, по одной.

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

Наличие в TeamCity актуальной успешной сборки мы проверяли при помощи метода REST API getAllBuilds примерно следующим образом (псевдокод):

haveFailed = False # Есть ли неудачные сборкиhaveActive = False # Есть ли активные сборки# Получаем сборки типа buildType для коммита commit ветки branchbuilds = teamCity.getAllBuilds(buildType, branch, commit)# Проверяем каждую сборкуfor build in builds:  # Проверяем каждую ревизию в сборке  for revision in build.revisions:    if revision.branch is branch and revision.commit is commit:      # Сборка актуальна      if build.isSuccessful:        # Сборка актуальна и успешна        return True      else if build.isRunning or build.isQueued        haveActive = True      else if build.isFailed:        haveFailed = Trueif haveFailed:  # Исключаем тикет из очереди, переоткрывая его  ticket = Jira.getTicket(branch.ticketKey)  ticket.reopen("Build Failed")  return Falseif not haveActiveBuilds:  # Нет ни активных, ни упавших, ни удачных сборок. Запускаем новую  TriggerBuild(buildType, branch)

Ревизии это коммиты, на основе которых TeamCity выполняет сборку. Они отображаются в виде 16-ричных последовательностей на вкладке Changes (Изменения) страницы сборки в веб-интерфейсе TeamCity. Благодаря ревизиям мы можем легко определить, требуется ли пересборка ветки тикета или тикет готов к слиянию.

Важно, что ревизию можно (а часто даже необходимо) указывать в запросе на добавление новой сборки в очередь в параметре lastChanges, потому что в противном случае TeamCity может выбрать устаревшую ревизию ветки при запуске сборки. Как будет показано ниже, указывать ревизию необходимо в тех случаях, если, например, логика вне TeamCity основана на поиске сборок на конкретных коммитах (наш случай).

Так как после перевода тикета в статус готовности (в нашем примере Resolved) соответствующая ветка, как правило, не меняется, то и сборка, ассоциированная с тикетом, чаще всего остаётся актуальной. Кроме того, сам факт нахождения тикета в статусе To Merge говорит о высокой вероятности того, что сборка не упала. Ведь при падении сборки мы сразу переоткрываем тикет.

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

Всё работало быстро, но требовало внимания. То и дело возникали ситуации, когда изменения нескольких тикетов конфликтовали между собой. Конфликты при слияниях как явление достаточно распространённое поначалу ни у кого особых вопросов не вызывали. Их разрешали разработчики, дежурные по релизу. Но с увеличением количества разработчиков, задач и, соответственно, веток, приведение релиза в порядок требовало всё больше усилий. Задержки в разрешении конфликтов начали сказываться на новых задачах. Полагаю, не стоит продолжать эту цепочку скорее всего, вы уже поняли, что я имею в виду. С конфликтами нужно было что-то делать, причём не допуская их попадания в релиз.

Конфликты слияния

Если изменить одну и ту же строку кода в разных ветках и попытаться соединить их в main, то Git попросит разрешить конфликты слияния. Из двух вариантов нужно выбрать один и закоммитить изменения.

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

Если команда git merge завершилась с ошибкой и для всех файлов в списке git ls-files --unmerged заданы обработчики конфликтов, то для каждого такого файла мы выполняем парсинг содержимого по маркерам конфликтов <<<<<<<, ======= и >>>>>>>. Если конфликты вызваны только изменением версии приложения, то, например, выбираем последнюю версию между локальной и удалённой частями конфликта.

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

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

Логические конфликты

А может ли случиться так, что, несмотря на успешность сборок пары веток в отдельности, после слияния их с main сборка на основной ветке упадёт? Практика показывает, что может. Например, если сумма a и b в каждой из двух веток не превышает 5, то это не гарантирует того, что совокупные изменения a и b в этих ветках не приведут к большей сумме.

Попробуем воспроизвести это на примере Bash-скрипта test.sh:

#!/bin/bashget_a() {    printf '%d\n' 1}get_b() {    printf '%d\n' 2}check_limit() {    local -i value="$1"    local -i limit="$2"    if (( value > limit )); then        printf >&2 '%d > %d%s\n' "$value" "$limit"        exit 1    fi}limit=5a=$(get_a)b=$(get_b)sum=$(( a + b ))check_limit "$a" "$limit"check_limit "$b" "$limit"check_limit "$sum" "$limit"printf 'OK\n'

Закоммитим его и создадим пару веток: a и b.
Пусть в первой ветке функция get_a() вернёт 3, а во второй get_b() вернёт 4:

diff --git a/test.sh b/test.shindex f118d07..39d3b53 100644--- a/test.sh+++ b/test.sh@@ -1,7 +1,7 @@ #!/bin/bash get_a() {-    printf '%d\n' 1+    printf '%d\n' 3 } get_b() {git diff main bdiff --git a/test.sh b/test.shindex f118d07..0bd80bb 100644--- a/test.sh+++ b/test.sh@@ -5,7 +5,7 @@ get_a() { }  get_b() {-    printf '%d\n' 2+    printf '%d\n' 4 }  check_limit() {

В обоих случаях сумма не превышает 5 и наш тест проходит успешно:

git checkout a && bash test.shSwitched to branch 'a'OKgit checkout b && bash test.shSwitched to branch 'b'OK

Но после слияния main с ветками тесты перестают проходить, несмотря на отсутствие явных конфликтов:

git merge a bFast-forwarding to: aTrying simple merge with bSimple merge did not work, trying automatic merge.Auto-merging test.shMerge made by the 'octopus' strategy. test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)bash test.sh7 > 5

Было бы проще, если бы вместо get_a() и get_b() использовались присваивания: a=1; b=2, заметит внимательный читатель и будет прав. Да, так было бы проще. Но, вероятно, именно поэтому встроенный алгоритм автомерджа Git успешно обнаружил бы конфликтную ситуацию (что не позволило бы продемонстрировать проблему логического конфликта):

git merge a Updating 4d4f90e..8b55df0Fast-forward test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)git merge b Auto-merging test.shCONFLICT (content): Merge conflict in test.shRecorded preimage for 'test.sh'Automatic merge failed; fix conflicts and then commit the result.

Разумеется, на практике конфликты бывают менее явными. Например, разные ветки могут полагаться на API разных версий какой-нибудь библиотеки зависимости, притом что более новая версия не поддерживает обратной совместимости. Без глубоких знаний кодовой базы (читай: без разработчиков проекта) обойтись вряд ли получится. Но ведь CI как раз и нужен для решения таких проблем.

Конечно, от разрешения конфликта мы никуда не уйдём кто-то должен внести правки. Но чем раньше нам удастся обнаружить проблему, тем меньше людей будет привлечено к её решению. В идеале потребуется озадачить лишь разработчика одной из конфликтующих веток. Если таких веток две, то одна из них вполне может быть соединена с main.

Превентивные меры

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

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

Вторая версия: последовательная стратегия

Стало ясно, что существующих условий готовности к автомерджу для тикета недостаточно. Требовалось какое-то средство синхронизации между ветками, какой-то порядок.

Git, по идее, как раз и является средством синхронизации. Но порядок попадания веток в main и, наоборот, main в ветки определяем мы сами. Чтобы определить точно, какие из веток вызывают проблемы в main, можно попробовать отправлять их туда по одной. Тогда можно выстроить их в очередь, а порядок организовать на основе времени попадания тикета в статус To Merge в стиле первый пришёл первым обслужен.

С порядком определились. А как дальше соединять ветки? Допустим, мы сольём в main первый тикет из очереди. Так как main изменилась, она может конфликтовать с остальными тикетами в очереди. Поэтому перед тем как сливать следующий тикет, нужно удостовериться, что обновлённая main по-прежнему совместима с ним. Для этого достаточно слить main в тикет. Но так как после соединения main с веткой её состояние отличается от того, которое было в сборке, необходимо перезапустить сборку. Для сохранения порядка все остальные тикеты в очереди должны ждать завершения сборки и обработки впередистоящих тикетов. Примерно такие рассуждения привели нас к последовательной стратегии автомерджа.

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

Но есть у этой схемы существенный недостаток: пропускная способность автомерджа линейно зависит от времени сборки. При среднем времени сборки iOS-приложения в 25 минут мы можем рассчитывать на прохождение максимум 57 тикетов в сутки. В случае же с Android-приложением требуется примерно 45 минут, что ограничивает автомердж 32 тикетами в сутки, а это даже меньше количества Android-разработчиков в нашей компании.

На практике время ожидания тикета в статусе To Merge составляло в среднем 2 часа 40 минут со всплесками, доходящими до 10 часов! Необходимость оптимизации стала очевидной. Нужно было увеличить скорость слияний, сохранив при этом стабильность последовательной стратегии.

Финальная версия: сочетание последовательной и жадной стратегий

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

Давайте вспомним идею жадной стратегии: мы сливали все ветки готовых тикетов в main. Основной проблемой было отсутствие синхронизации между ветками. Решив её, мы получим быстрый и надёжный автомердж!

Раз нужно оценить общий вклад всех тикетов в статусе To Merge в main, то почему бы не слить все ветки в некоторую промежуточную ветку Main Candidate (MC) и не запустить сборку на ней? Если сборка окажется успешной, то можно смело сливать MC в main. В противном случае придётся исключать часть тикетов из MC и запускать сборку заново.

Как понять, какие тикеты исключить? Допустим, у нас n тикетов. На практике причиной падения сборки чаще всего является один тикет. Где он находится, мы не знаем все позиции от 1 до n являются равноценными. Поэтому для поиска проблемного тикета мы делим n пополам.

Так как место тикета в очереди определяется временем его попадания в статус To Merge, имеет смысл брать ту половину, в которой расположены тикеты с большим временем ожидания.

Следуя этому алгоритму, для k проблемных тикетов в худшем случае нам придётся выполнить O(k*log2(n)) сборок, прежде чем мы обработаем все проблемные тикеты и получим удачную сборку на оставшихся.

Вероятность благоприятного исхода велика. А ещё в то время, пока сборки на ветке MC падают, мы можем продолжать работу при помощи последовательного алгоритма!

Итак, у нас есть две автономные модели автомерджа: последовательная (назовём её Sequential Merge, или SM) и жадная (назовём её Greedy Merge, или GM). Чтобы получить пользу от обеих, нужно дать им возможность работать параллельно. А параллельные процессы требуют синхронизации, которой можно добиться либо средствами межпроцессного взаимодействия, либо неблокирующей синхронизацией, либо сочетанием этих двух методов. Во всяком случае, мне другие методы неизвестны.

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

Остаётся предотвратить все возможные случаи состояний гонки. Их много, но для понимания сути приведу несколько самых важных:

  1. SM-SM и GM-GM: между командами одного типа.

  2. SM-GM: между SM и GM в рамках одного репозитория.

Первая проблема легко решается при помощи мьютекса по токену, включающему в себя имя команды и название репозитория. Пример: lock_${command}_${repository}.

Поясню, в чём заключается сложность второго случая. Если SM и GM будут действовать несогласованно, то может случиться так, что SM соединит main с первым тикетом из очереди, а GM этого тикета не заметит, то есть соберёт все остальные тикеты без учёта первого. Например, если SM переведёт тикет в статус In Master, а GM будет всегда выбирать тикеты по статусу To Merge, то GM может никогда не обработать тикета, соединённого SM. При этом тот самый первый тикет может конфликтовать как минимум с одним из других.

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

Таким образом, мы получили своего рода неблокирующую синхронизацию.

Немного о TeamCity

В процессе реализации GM нам предстояло обработать много нюансов, которыми я не хочу перегружать статью. Но один из них заслуживает внимания. В ходе разработки я столкнулся с проблемой зацикливания команды GM: процесс постоянно пересобирал ветку MC и создавал новую сборку в TeamCity. Проблема оказалась в том, что TeamCity не успел скачать обновления репозитория, в которых была ветка MC, созданная процессом GM несколько секунд назад. К слову, интервал обновления репозитория в TeamCity у нас составляет примерно 30 секунд.

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

Кто-то посчитает решение очевидным, но я нашёл его не сразу. Оказывается, прикрепить ревизию к сборке при её добавлении в очередь можно при помощи параметра lastChanges метода addBuildToQueue:

<lastChanges>  <change    locator="version:{{revision}},buildType:(id:{{build_type}})"/></lastChanges>

В этом примере {{revision}} заменяется на 16-ричную последовательность коммита, а {{build_type}} на идентификатор конфигурации сборки. Но этого недостаточно, так как TeamCity, не имея информации о новом коммите, может отказать нам в запросе.

Для того чтобы новый коммит дошёл до TeamCity, нужно либо подождать примерно столько, сколько указано в настройках конфигурации корня VCS, либо попросить TeamCity проверить наличие изменений в репозитории (Pending Changes) при помощи метода requestPendingChangesCheck, а затем подождать, пока TeamCity скачает изменения, содержащие наш коммит. Проверка такого рода выполняется посредством метода getChange, где в changeLocator нужно передать как минимум сам коммит в качестве параметра локатора version. Кстати, на момент написания статьи (и кода) на странице ChangeLocator в официальной документации описание параметра version отсутствовало. Быть может, поэтому я не сразу узнал о его существовании и о том, что это 40-символьный 16-ричный хеш коммита.

Псевдокод:

teamCity.requestPendingChanges(buildType)attempt = 1while attempt <= 20:  response = teamCity.getChange(commit, buildType)  if response.commit == commit:    return True # Дождались  sleep(10)return False

О предельно высокой скорости слияний

У жадной стратегии есть недостаток на поиск ветки с ошибкой может потребоваться много времени. Например, 6 сборок для 20 тикетов у нас может занять около трёх часов. Можно ли устранить этот недостаток?

Допустим, в очереди находится 10 тикетов, среди которых только 6-й приводит к падению сборки.

Согласно жадной стратегии, мы пробуем собрать сразу все 10 тикетов, что приводит к падению сборки. Далее собираем левую половину (с 1 по 5) успешно, так как тикет с ошибкой остался в правой половине.

Если бы мы сразу запустили сборку на левой половине очереди, то не потеряли бы времени. А если бы проблемным оказался не 6-й тикет, а 4-й, то было бы выгодно запустить сборку на четверти длины всей очереди, то есть на тикетах с 1 по 3, например.

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

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

Примерно такой же алгоритм реализован в премиум-функции GitLab под названием Merge Trains. Перевода этого названия на русский язык я не нашёл, поэтому назову его Поезда слияний. Поезд представляет собой очередь запросов на слияние с основной веткой (merge requests). Для каждого такого запроса выполняется слияние изменений ветки самого запроса с изменениями всех запросов, расположенных перед ним (то есть запросов, добавленных в поезд ранее). Например, для трёх запросов на слияние A, B и С GitLab создаёт следующие сборки:

  1. Изменения из А, соединённые с основной веткой.

  2. Изменения из A и B, соединённые с основной веткой.

  3. Изменения из A, B и C, соединённые с основной веткой.

Если сборка падает, то соответствующий запрос из очереди удаляется, а сборки всех предыдущих запросов перезапускаются (без учёта удалённого запроса).

GitLab ограничивает количество параллельно работающих сборок двадцатью. Все остальные сборки попадают в очередь ожидания вне поезда. Как только сборка завершает работу, её место занимает очередная сборка из очереди ожидания.

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

Но если преград человеческой мысли нет, то пределы аппаратных ресурсов видны достаточно отчётливо:

  1. Каждой сборке нужен свой агент в TeamCity.

  2. В нашем случае у сборки мобильного приложения есть порядка 15-100 сборок-зависимостей, каждой из которых нужно выделить по агенту.

  3. Сборки автомерджа мобильных приложений в main составляют лишь малую часть от общего количества сборок в TeamCity.

Взвесив все плюсы и минусы, мы решили пока остановиться на алгоритме SM + GM. При текущей скорости роста очереди тикетов алгоритм показывает хорошие результаты. Если в будущем заметим возможные проблемы с пропускной способностью, то, вероятно, пойдём в сторону Merge Trains и добавим пару параллельных сборок GM:

  1. Вся очередь.

  2. Левая половина очереди.

  3. Левая четверть очереди.

Что в итоге получилось

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

  • уменьшение среднего размера очереди в 2-3 раза;

  • уменьшение среднего времени ожидания в 4-5 раз;

  • мердж порядка 50 веток в день в каждом из упомянутых проектов;

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

Примеры графиков слияний за несколько дней:

Количество тикетов в очереди до и после внедрения нового алгоритма:

Среднее количество тикетов в очереди (AVG) уменьшилось в 2,5 раза (3,95/1,55).

Время ожидания тикетов в минутах:

Среднее время ожидания (AVG) уменьшилось в 4,4 раза (155,5/35,07).

Подробнее..

Нюансы использования TeamCity

20.12.2020 12:12:18 | Автор: admin

Картинка


Всем привет.


Статья написана в простом стиле "DevOps для домохозяек" от таких же домохозяек. В ней будет описано с какими неожиданностями можно столкнуться при настройке проекта в TeamCity. Также приведу рекомендации как эти проблемы можно обойти.


Нижеописанное основано на моём двухлетнем опыте настройке TeamCity сборок, чтению баг репортов и обмене мнений с коллегами по цеху. Не претендую на истину в последней инстанции, так как в работе в основном использовался подход SDD (Stackoverflow Driven Development).


Небольшая справка:


  • TeamCity CI (Continous Integration) инструмент. "Аналог" Gitlab CI, Github Actions с прицелом на возможность полной настройки автоматизации из графического интерфейса.
  • Проект (Project) агрегирующая сущность, в неё связываются несколько сборок. В TeamCity древовидная структура проект->подпроект->сборка с частичным наследованием настроек.
  • Сборка (Build) Атомарная сущность автоматизации. Примеры сборок "Запуск автотестов", "Установка конфигурации", "Сборка дистрибутива". Каждая сборка состоит из нескольких шагов.
  • Шаг (Build step) Описание "а что нужно делать" используя разные "runner type". Это может быть как простой Bash скрипт, так и запуск Docker контейнера.

Вкратце по проекту TeamCity с которым я работаю:


  • ~30 сборок, шаги сборок состоят из вызовов Bash, Ansible и Python.
  • Никаких сборок Android приложений, Web проектов, Docker, k8s и прочего. Просто заказ облачных серверов, подъем базы данных из дампа, установка программ и конфигурации.
  • Настройка ведётся из графического интерфейса, без Kotlin DSL (переход на него в планах).

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


1 Нельзя изменить параметры сборки при запуске по триггеру


Сборки можно запускать по триггеру (внешнему событию). Триггеры могут быть разные: была завершена другая сборка, обновилась git ветка, cron задача. При этом в сборке можно задать параметры по умолчанию.


Так вот: запуск по триггеру можно сделать только с параметрами по умолчанию. На эту проблему есть нерешённая задача 2008 года.


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


Но мне возразят, что нужно использовать build chain (цепочку сборок). Окей, давайте посмотрим что там не так.


2 Build chain or not просто скопируй ещё сборки


В случае вышеописанного кейса (заказ стенда + прогон автотестов) мы настраиваем build chain. В таком случае если нам нужен стенд, то мы его получаем из сборки запуска автотестов. Интуитивно понятно, не правда ли?


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


Но как тогда брать имя стенда, на котором запускать автотесты? Если у нас две сборки отдельных, то мы указываем имя в параметрах. Если цепочка сборок то проще всего использовать артефакт. А теперь если мы желаем запускать и отдельно, и вместе, то нужен специальный огород, который будет это всё обрабатывать. Осталось только представить, как будет "интересно" настраивать такой огород, когда у нас появится две разные сборки на заказ стенда (заказ идёт в разных облаках, разные программы), а сборка с запуском автотестов будет одна.


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


3 Переопределение параметров зависимой сборки


Рассмотрим другой пример: у нас есть три зависимые последовательные сборки, которые связаны в build chain. Скажем заказ в облаке стенда, установка дампа базы данных и установка программ. Мы "интуитивно" запускаем сборку по установке программ и возникает вопрос: а как пробросить размер заказываемой машины в зависимой сборке? И тут нам на помощь приходит переопределение параметров.


Теперь у нас в одном диалоговом окне по запуску сборке возникает 3*N параметров, которые никак не отличаются друг от друга. Ещё стоит учитывать, что описание и параметры по умолчанию таких параметров не копируются, их нужно копировать отдельно. Особенно это "радует", когда эти описания и значения меняются. Их тогда нужно будет обновлять в N местах, если сборки можно вызывать из разных мест как в нашем случае. Например, нужен человеку только стенд с дампом базы данных, он тогда вправе заказать его со второй сборки. А там в параметрах версия дампа устаревшая, в отличие от последней сборки цепочки, и пойдёт разбор полётов на полдня почему дамп кривой.


И конечно тут не будет никакой валидации, что вы не ошиблись в имени переопределяемого параметра, всё в лучших традициях YAML Developer'ов.


4 Конфигурация сборки может быть только одна


Проблема не относится к Kotlin DSL (у меня нет опыта его использования, не могу сказать насколько эта проблема действительно решается). Если мы настраиваем сборки в графическом интерфейсе как настоящие домохозяйки, то сталкиваемся со следующей проблемой: а как плавно поменять настройки проекта, так чтобы это не коснулось пользователей?


Первый и самый простой вариант: объявить технологические работы и править "на горячую". Второй вариант: скопировать сборку в отдельное место и делать изменения в ней (наш вариант).


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


Рекомендация: не архивируйте/удаляйте старые сборки, а обновляете их после внесения изменений в основную ветку кода. Всегда найдутся люди, у которых ссылки на сборки хранятся где-то в закладках и если вы поменяется ID сборки, то все ссылки побьются.


5 TeamCity API


Я думаю многие здесь знакомы с "главными" 4 метриками DevOps. И TeamCity кажется идеальным местом, чтобы собрать всю информацию хотя бы о половине из них ("Deployment Frequency" и "Lead Time for Changes").


Иии вот нельзя в API быстро узнать процент упавших сборок, частоту запуска и причины падения. Да, там есть какие-то дашборды, но информация в них именно та, которая не нужна. То есть вот начали у нас падать все сборки на основной ветке, и мы можем только вручную "Assign investigation", либо придумывать как реализовывать такой инструмент в каждой сборке. Не очень удобно.


Однако, в чём хорош API так это в формировании build chain из-за вышеперечисленных недостатков с "нативным" способом. В таком случае можно сборки создавать для независимого запуска. А их связывание делать в отдельной сборке с запуском тупого Python скрипта. И много кто так обходит проблему.


6 При запуске Bash скрипта проверяется только результат последней команды


Есть у нас простой скрипт, написанный в интерфейсе:


./command_1.sh # always faills # always success

В таком случае этот шаг сборки будет всегда зелёный. Но если мы добавим мантру:


./command_1.sh # always failif [ $? -ne 0 ]; then  echo "##teamcity[buildProblem description='Build failed']"fils # always success

И тогда уже шаг будет красным, и сборка дальше не пойдёт (тут уже как выставлен "Execute step"). Иными словами, всегда нужно учитывать особенность работы Bash скриптов.


7 Работа с шифрованными параметрами сборки


В TeamCity можно добавить параметры-секреты, такие как пароли и API ключи. Чтобы такие данные не утекли, в логах сборки ищутся значения таких параметров и заменяются на символы *. И возникает следующий нюанс: а если нам эти параметры нужно записать в другой файл. Команда echo в таком случае не сработает фильтр перехватит. В итоге мы пришли к следующему варианту:


cat > constants.json <<- EOM{    "key": "%value%"}EOM

Задача, в которой это понадобилась, была следующая. Есть Python скрипт, который выполняет запросы к нескольким системам, и вся его конфигурация сохранена в JSON. Как к нему подать секреты? Можно через командную строку, но тогда у нас растекается конфигурация сразу по четырём местам: JSON, командная строка, значение по умолчанию в скрипте и ещё значение по умолчанию в параметре TeamCity. Поскольку скрипт должен быть тупым и одноразовым, то решили максимально упростить: всю конфигурацию втащить в JSON. JSON прям с вписанными именами параметров TeamCity сохраняем в репозиторий и копируем как есть в шаг сборки. В итоге мы сразу формируем нужный JSON и не разбираемся какой параметр, где нужен.


8 Скорость прогрузки графического интерфейса


Это будет очень субъективный пункт. Поскольку основная работа по настройке проводится в интерфейсе (для тех кто не пользуется связкой Kotlin DSL + TeamCity API), то производительность работы пропорционально скорости работы этого интерфейса. А он ооочень медленный. Я постарался в меру своих интеллектуальных способностей замерить скорость прогрузки и вот какие цифры получил (был использован браузер Firefox и инструмент Network).


  • Загрузка окно проекта со всеми сборками и вызов окна запуска сборки
    • load: 9.87 s
    • DOMContentLoaded: 4.92 s
    • Finish: 34.39 s
    • Size/transferred size of all requests: 10.69 MB / 2.42 MB
    • Requests: 345
  • Загрузка окна отдельной сборки и вызов окна запуска сборки
    • load: 4.59 s
    • DOMContentLoaded: 1.27 s
    • Finish: 27.42 s
    • Size/transferred size of all requests: 11.53 MB / 2.23 MB
    • Requests: 120

Время Finish до момента как у меня появляется возможность запустить сборку. Так как после этого ещё в фоне прогружается страница и идут запросы. Полминуты чтобы просто запустить одну сборку, неплохо?


9 Информация по упавшей сборке


Это будет ещё один субъективный пункт. Для каждой сборки есть вкладка Overview. В ней в случае падения сборки указывается ошибка. И эта ошибка в 99% случаев определяется неправильно. В нашем случае (может у кого по-другому) ошибка определяется как "первое, что попало в stderr", хотя было бы логичнее сделать "последнее, что попало в stderr". В случае Ansible это всегда будет какой-нибудь "WARNING: Deprecation setting...". И в итоге это вызывает стабильный поток вопросов у людей слабо знакомых с TeamCity. Пусть лучше вообще там ничего не писалось.


10 Вечные проблемы с агентами


Здесь я бы хотел написать про все проблемы, которые связанные с агентами сборки (Build agents). Как известно в TeamCity есть master сервер, который выполняет роль планировщика, а сами сборки запускаются на отдельных серверах. И нужно уметь правильно с этими агентами работать (обслуживать), TeamCity тут мало что может сделать.


Первая проблема удаление агентов. У агентов чаще всего есть какой-то срок жизни, их лучше не делать долгоживущими, иначе потом появляется дрейф конфигурации. Например, кто-то поменял JAVA_HOME и понеслось. И вот это удаление может прилетать вообще неожиданно. Планировщик выдал агента для тяжеловесной ночной десятичасовой сборки. Но ночью чаще всего проводятся все работы по обслуживанию и какой-то сервис, не проверив что там с агентом просто его грохает. Мы так и не победили эту проблему (администрированием TeamCity занимается отдельная "команда").


Вторая проблема закончившееся место на агенте, либо неработающая базовая утилита. Пересекается с первым пунктом, но тут "веселее". Запускаем сборку, на самом первом шаге это всё падает и агент снова бодро готов браться за новую работу. Мы раздражённо запускаем сборку заново и по великому везению попадается тот самый агент и по новой. "Но у нас же есть великая настройка по выбору агента!" скажете вы и будете правы. Только один нюанс: а если у нас build chain? Тутуту руру тутуту, а оказывается, что выбрать агент можно только на текущую сборку, на зависимые может браться какой угодно и мы знаем какой будет выбран по закону подлости. Но это в случае, если вы не выставили при установке зависимой сборки "Run build on the same agent". Но вы же выставили, правда?


Третья проблема дрейф конфигурации на агентах. На агентах должно быть неизменяемое окружение (то, что не должно быть root прав, я думаю объяснять не надо). Кто-то поменял переменную окружения, поменял локальные пути до утилит и понеслось. Начинаешь после каждого такого случая перестраховываться и потом у тебя 90% сборки это подготовка агента к твоему print("Hello, World!").


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

Подробнее..
Категории: Системы сборки , Ci , Devops , Teamcity

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru