Skip to main content
Мы публикуем частые обновления нашей документации, и перевод этой страницы может все еще выполняться. Актуальные сведения см. в документации на английском языке.
В настоящее время GitHub AE находится в ограниченном выпуске.

Создание тестов CI с помощью API проверок

Создайте сервер непрерывной интеграции для выполнения тестов с помощью GitHub App и API проверок.

Введение

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

CI — это практика программного обеспечения, которая требует частой фиксации кода в общем репозитории. Фиксация кода быстрее и чаще вызывает ошибки и уменьшает объем кода, отладку которого разработчику необходимо выполнить при поиске источника ошибки. Частые обновления кода также упрощают слияние изменений, полученные от разных участников группы разработчиков программного обеспечения. Это отлично подходит для разработчиков, которые могут тратить больше времени на написание кода и меньше времени на отладку ошибок или разрешение конфликтов слияния. 🙌

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

Примечание. В этом руководстве демонстрируется процесс разработки приложений с использованием языка программирования Ruby. Однако существуют и другие способы применения Octokit. Если вы предпочитаете JavaScript, то для разработки приложений GitHub можно использовать Probot и Node.js.

Обзор API проверок

API проверок позволяет настроить тесты CI, которые автоматически выполняются для каждой фиксации кода в репозитории. API проверок сообщает дополнительные сведения о каждой проверке в GitHub на вкладке Проверки запроса на вытягивание. С помощью API проверок можно создавать заметки с дополнительными сведениями для конкретных строк кода. Заметки отображаются на вкладке Проверки. При создании заметки для файла, который является частью запроса на вытягивание, заметки также отображаются на вкладке Измененные файлы.

Набор проверок — это группа запусков проверок (отдельные тесты CI). Набор и запуски содержат состояния, которые отображаются в запросе на вытягивание в GitHub. Вы можете использовать состояния, чтобы определить, когда фиксация кода вызывает ошибки. При использовании этих состояний с защищенными ветвями можно предотвратить преждевременное слияние запросов на вытягивание. Дополнительные сведения см. в разделе Сведения о защищенных ветвях.

API проверок отправляет событие веб-перехватчика check_suite всем приложениям GitHub, установленным в репозитории, при каждом отправлении нового кода в репозиторий. Чтобы получить все действия событий API проверок, приложение должно иметь разрешение checks:write. GitHub автоматически создает события check_suite для новых фиксаций кода в репозитории с помощью потока по умолчанию, но при необходимости можно обновить параметры репозитория для наборов проверок . Этот поток по умолчанию выполняется следующим образом:

  1. Всякий раз, когда кто-то отправляет код в репозиторий, GitHub отправляет событие check_suite с действием requested для всех приложений GitHub, установленных в репозитории с разрешениемchecks:write. Это событие сообщает приложениям о том, что код был отправлен и что GitHub автоматически создал новый набор проверок.
  2. Когда приложение получает это событие, оно может добавить выполнения проверки в этот набор.
  3. Выполнения проверки могут включать заметки, отображаемые в определенных строках кода.

Из этого руководства вы узнаете, как выполнить следующие задачи:

  • Часть 1. Настройка платформы для сервера CI с помощью API проверок.
    • Настройте приложение GitHub в качестве сервера, который получает события API проверок.
    • Создайте новые выполнения проверки для тестов CI, когда репозиторий получает только что отправленные фиксации.
    • Повторная проверка выполняется, когда пользователь запрашивает это действие в GitHub.
  • Часть 2. Создание серверной платформы CI, созданной путем добавления теста CI анализатора кода.
    • Обновите выполнение проверки с помощью сведений status, conclusion и output.
    • Создайте заметки в строках кода, которые GitHub отображает на вкладках Проверки и Измененные файлы в запросе на вытягивание.
    • Автоматически исправьте рекомендации анализатора кода путем предоставления кнопки "Исправить это" на вкладке Проверки в запросе на вытягивание.

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

Демонстрационная версия краткого руководства по серверу CI API проверок

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

Прежде чем приступить к работе, вы можете ознакомиться с приложениями GitHub, веб-перехватчиками и API проверок, если вы еще не сделали этого. Дополнительные API-интерфейсы можно найти в документации по REST API. API проверок также можно использовать в GraphQL, но в этом кратком руководстве основное внимание уделяется REST. Дополнительные сведения см. в объектах GraphQL Набор проверок и Выполнение проверки.

Вы будете использовать язык программирования Ruby, службу доставки полезных данных веб-перехватчика Smee, библиотеку Octokit.rb Ruby для REST API GitHub и веб-платформу Sinatra, чтобы создать серверное приложение CI API проверок.

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

  1. Клонируйте репозиторий Создание тестов CI с помощью API проверок.

    $ git clone https://github.com/github-developer/creating-ci-tests-with-the-checks-api.git

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

  2. Выполните действия, описанные в кратком руководстве Настройка среды разработки, чтобы настроить и запустить сервер приложений. Примечание. Вместо клонирования репозитория шаблонов приложений GitHub используйте файл template_server.rb в репозитории, клонированном на предыдущем шаге в этом кратком руководстве.

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

    Если у вас возникли проблемы с настройкой шаблона приложения GitHub, ознакомьтесь с разделом Устранение неполадок.

Часть 1. Создание API проверок

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

Выполнение проверки не будет запускать никаких проверок кода в этом разделе. Вы добавите эту функциональную возможность при работе со статьей Часть 2. Создание теста CI Octo RuboCop.

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

Приступим к работе! Ниже указанны шаги, которые вы выполните в части 1.

  1. Обновление разрешений приложения
  2. Добавление обработки событий
  3. Создание выполнения проверки
  4. Обновление выполнения проверки

Шаг 1.1. Обновление разрешений приложения

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

Чтобы обновить разрешения приложения:

  1. Выберите приложение на странице параметров приложения и щелкните Разрешения и веб-перехватчики на боковой панели.
  2. В разделе "Разрешения" откройте пункт "Проверки" и выберите Чтение и запись в раскрывающемся списке "Доступ" рядом с ним.
  3. В разделе "Оформление подписки на события" выберите Набор проверок и Выполнение проверки, чтобы подписаться на эти события.
  4. Нажмите Сохранить изменения в нижней части страницы.
  5. Если вы установили приложение в своей учетной записи, проверьте свой почтовый ящик и перейдите по ссылке, чтобы принять новые разрешения. Каждый раз, когда вы изменяете разрешения или веб-перехватчики приложения, пользователи, которые установили приложение (включая вас самих), должны принять новые разрешения, прежде чем изменения вступят в силу. Чтобы принять новые разрешения, можно также перейти на страницу установки и щелкнуть "Настроить" рядом с приложением. В верхней части страницы появится баннер, сообщающий, что приложение запрашивает различные разрешения. Щелкните "Сведения" и нажмите "Принять новые разрешения".

Отлично! Ваше приложение имеет разрешение на выполнение необходимых задач. Теперь можно добавить код для обработки событий.

Шаг 1.2. Добавление обработки событий

Теперь, когда приложение подписано на события Набор проверок и Выполнение проверки, оно начнет получать веб-перехватчики check_suite и check_run. GitHub отправляет полезные данные веб-перехватчика в виде запросов POST. Так как вы перенаправили полезные данные веб-перехватчика Smee в http://localhost/event_handler:3000, сервер получит полезные данные запроса POST на маршруте post '/event_handler'.

Пустой маршрут post '/event_handler' уже включен в файл template_server.rb, который вы скачали в разделе предварительных требований. Пустой маршрут выглядит следующим образом:

  post '/event_handler' do

    # # # # # # # # # # # #
    # ADD YOUR CODE HERE  #
    # # # # # # # # # # # #

    200 # success status
  end

Используйте этот маршрут для обработки события check_suite, добавив следующий код:

# Get the event type from the HTTP_X_GITHUB_EVENT header
case request.env['HTTP_X_GITHUB_EVENT']
when 'check_suite'
  # A new check_suite has been created. Create a new check run with status queued
  if @payload['action'] == 'requested' || @payload['action'] == 'rerequested'
    create_check_run
  end
end

Каждое событие, которое отправляет GitHub, включает в себя заголовок запроса с именем HTTP_X_GITHUB_EVENT, который указывает тип события в запросе POST. Сейчас вас интересуют только события типа check_suite, которые возникают при создании нового набора проверок. Каждое событие имеет дополнительное поле action, указывающее тип действия, которое активировало события. Для check_suite поле action может находится в состоянии requested, rerequested или completed.

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

Шаг 1.3. Создание выполнения проверки

Добавьте этот новый метод в качестве вспомогательного приложения Sinatra, если необходимо, чтобы другие маршруты также использовали его. В helpers do добавьте следующий метод create_check_run:

# Create a new check run with the status queued
def create_check_run
  @installation_client.create_check_run(
    # [String, Integer, Hash, Octokit Repository object] A GitHub repository.
    @payload['repository']['full_name'],
    # [String] The name of your check run.
    'Octo RuboCop',
    # [String] The SHA of the commit to check 
    # The payload structure differs depending on whether a check run or a check suite event occurred.
    @payload['check_run'].nil? ? @payload['check_suite']['head_sha'] : @payload['check_run']['head_sha'],
    # [Hash] 'Accept' header option, to avoid a warning about the API not being ready for production use.
    accept: 'application/vnd.github+json'
  )
end

Этот код вызывает конечную точку Создание выполнения проверки с помощью метода create_check_run.

Чтобы создать выполнение проверки, требуются только два входных параметра: name и head_sha. Мы будем использовать RuboCop для реализации теста CI далее в этом кратком руководстве, поэтому здесь используется имя Octo RuboCop, но вы можете выбрать любое имя для выполнения проверки.

Теперь вы предоставляете только необходимые параметры, чтобы получить базовые функции, но вы обновите выполнение проверки позже во время сбора дополнительных сведений о нем. По умолчанию для status GitHub задает значение queued.

GitHub создает выполнение проверки для определенной фиксации SHA, поэтому head_sha является обязательным параметром. SHA фиксации можно найти в полезных данных веб-перехватчика. Несмотря на то, что вы создаете только выполнение проверки для события check_suite прямо сейчас, будет не лишним знать, что head_sha включено в объекты check_suite и check_run в полезных данных события.

В указанном коде используется тернарный оператор, который работает как инструкция if/else, чтобы проверить, содержат ли полезные данные объект check_run. Если это так, вы считываете head_sha из объекта check_run, в противном случае вы считываете его из объекта check_suite.

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

$ ruby template_server.rb

Примечание. Прежде чем тестировать изменения, необходимо перезапустить сервер Sinatra. Введите Ctrl-C, чтобы остановить сервер, а затем снова выполните ruby template_server.rb. Если вы не хотите делать это при каждом изменении в коде приложения, можно использовать перезагрузку.

Теперь откройте запрос на вытягивание в репозитории, где установлено приложение. В ответ ваше приложение должно создать выполнение проверки в запросе на вытягивание. Щелкните вкладку Проверки, и вы увидите нечто вроде этого:

Выполнение проверки в очереди

Если на вкладке "Проверки" отображаются другие приложения, это означает, что в репозитории установлены другие приложения с доступом на Чтение и запись для проверок и вы подписаны на события Набор проверок и Выполнение проверки.

Отлично! Вы указали GitHub создать выполнение проверки. Отображается состояние выполнения проверки queued рядом с желтым значком. Затем необходимо подождать, пока GitHub создаст выполнение проверки и обновит ее состояние.

Шаг 1.4. Обновление выполнения проверки

При выполнении метода create_check_run запрашивается создание нового выполнения проверки в GitHub. Когда GitHub завершит создание выполнения проверки, вы получите событие веб-перехватчика check_run с действием created. Это событие является вашим сигналом для начала выполнения проверки.

Вы понадобится обновить обработчик событий для поиска действия created. При обновлении обработчика событий можно добавить условие для действия rerequested. Когда кто-то повторно запускает один тест на GitHub, нажав кнопку "Повторный запуск", GitHub отправляет событие выполнения проверки rerequested в приложение. При выполнении проверки rerequested необходимо запустить весь процесс и создать новое выполнение проверки.

Чтобы включить условие события check_run в маршрут post '/event_handler', добавьте в него следующий код case request.env['HTTP_X_GITHUB_EVENT']:

when 'check_run'
  # Check that the event is being sent to this app
  if @payload['check_run']['app']['id'].to_s === APP_IDENTIFIER
    case @payload['action']
    when 'created'
      initiate_check_run
    when 'rerequested'
      create_check_run
    end
  end

GitHub отправляет все события для выполнений проверки created в каждое приложение, установленное в репозитории с необходимыми разрешениями проверок. Это означает, что ваше приложение будет получать выполнения проверки, созданные другими приложениями. Выполнение проверки created несколько отличается от набора проверок requested или rerequested, который GitHub отправляет только приложениям, запрашиваемым для выполнения проверки. Указанный код ищет идентификатор приложения для выполнения проверки. При этом выполняется фильтрация всех выполнений проверки для других приложений в репозитории.

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

В этом разделе вы еще не будете запускать тест CI, но узнаете, как изменить состояние выполнения проверки с queued на pending, а затем с pending на completed, чтобы увидеть общий поток выполнения проверки. В статье Часть 2. Создание теста CI Octo RuboCop вы добавите код, который фактически выполняет тест CI.

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

# Start the CI process
def initiate_check_run
  # Once the check run is created, you'll update the status of the check run
  # to 'in_progress' and run the CI process. When the CI finishes, you'll
  # update the check run status to 'completed' and add the CI results.

  @installation_client.update_check_run(
    @payload['repository']['full_name'],
    @payload['check_run']['id'],
    status: 'in_progress',
    accept: 'application/vnd.github+json'
  )

  # ***** RUN A CI TEST *****

  # Mark the check run as complete!
  @installation_client.update_check_run(
    @payload['repository']['full_name'],
    @payload['check_run']['id'],
    status: 'completed',
    conclusion: 'success',
    accept: 'application/vnd.github+json'
  )
end

Указанный код вызывает конечную точку API Обновление выполнения проверки с помощью update_check_run метода Octokit для обновления уже созданного выполнения проверки.

Вот что делает этот код. Во-первых, он обновляет состояние выполнения проверки in_progress и неявно задает значение started_at для текущего времени. В части 2 этого краткого руководства вы добавите код, который запускает реальный тест CI в разделе ***** RUN A CI TEST *****. Пока оставьте этот раздел в качестве заполнителя, поэтому код, который следует за ним, будет просто имитировать успешность процесса CI и прохождение всех тестов. Наконец, код обновляет состояние выполнения проверки до completed.

В документации по обновлению выполнения проверки вы заметите, что при указании состояния необходимо задать параметры completed``conclusion и completed_at. conclusion суммирует результат выполнения проверки и может иметь значение success, failure, neutral, cancelled, timed_out или action_required. Вы задали значение success, значение completed_at для текущего времени и значение completed для состояния.

Вы также можете предоставить дополнительные сведения о том, что делает ваша проверка, но вы перейдете к ним в следующем разделе. Давайте протестируем этот код еще раз, повторно выполнив команду template_server.rb:

$ ruby template_server.rb

Перейдите к открытому запросу на вытягивание и щелкните вкладку Проверки. Нажмите кнопку "Повторно запустить все" в левом верхнем углу. Вы увидите, что выполнение проверки переходит от pending к in_progress и заканчивается с результатом success:

Завершенное выполнение проверки

Часть 2. Создание теста CI Octo RuboCop

RuboCop — это анализатор кода Ruby и форматировщик. Он проверяет код Ruby, чтобы убедиться в соответствии руководству по стилю Ruby. RuboCop располагает тремя основными функциями:

  • Анализ кода для проверки стиля кода
  • Форматирование кода
  • Заменяет собственные возможности анализа кода Ruby с помощью ruby -w

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

Приложение будет запускать RuboCop на сервере CI и создавать выполнения проверки (в этом случае тесты CI), которые сообщают результаты, которые RuboCop сообщает GitHub.

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

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

Чтобы воспользоваться преимуществами запрошенных действий, разработчики приложений могут создавать кнопки на вкладке Проверки запросов на вытягивание. Когда кто-то нажимает одну из этих кнопок, нажатие отправляет событие requested_action check_run в приложение GitHub. Действие, выполняемое приложением, полностью настраивается разработчиком приложения. В этом кратком руководстве описано, как добавить кнопку, которая позволяет пользователям запрашивать исправление ошибок, которые она находит. RuboCop поддерживает автоматическое исправление ошибок с помощью параметра командной строки, и вы настроите requested_action, чтобы воспользоваться преимуществами этого параметра.

Приступим к работе! Ниже указанны шаги, которые вы выполните при работе с этим разделом.

  1. Добавление файла Ruby
  2. Клонирование репозитория
  3. Запуск RuboCop
  4. Сбор ошибок RuboCop
  5. Обновление выполнения проверки с помощью результатов теста CI
  6. Автоматическое исправление ошибок RuboCop
  7. Советы по безопасности

Шаг 2.1. Добавление файла Ruby

Вы можете передать определенные файлы или целые каталоги в RuboCop для проверки. В этом кратком руководстве описано, как запустить RuboCop во всем каталоге. Так как RuboCop проверяет только код Ruby, вам потребуется по крайней мере один файл Ruby в репозитории, содержащем ошибки. Указанный ниже пример файла содержит несколько ошибок. Добавьте этот пример файла Ruby в репозиторий, в котором установлено приложение (обязательно присвойте имя файлу с расширением .rb, как показано в myfile.rb):

# The Octocat class tells you about different breeds of Octocat
class Octocat
  def initialize(name, *breeds)
    # Instance variables
    @name = name
    @breeds = breeds
  end

  def display
    breed = @breeds.join("-")

    puts "I am of #{breed} breed, and my name is #{@name}."
  end
end

m = Octocat.new("Mona", "cat", "octopus")
m.display

Шаг 2.2. Клонирование репозитория

RuboCop доступен в виде служебной программы командной строки. Это означает, что приложению GitHub потребуется клонировать локальную копию репозитория на сервере CI, чтобы RuboCop смог проанализировать файлы. Для выполнения операций Git в приложении Ruby можно использовать драгоценный камень ruby-git.

Gemfile в репозитории building-a-checks-api-ci-server уже содержит драгоценный камень ruby-git, установленный при выполнении bundle install на предварительных этапах. Чтобы использовать драгоценный камень, добавьте этот код в начало файла template_server.rb:

require 'git'

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

  1. Выберите приложение на странице параметров приложения и щелкните Разрешения и веб-перехватчики на боковой панели.
  2. В разделе "Разрешения" найдите элемент "Содержимое репозитория" и выберите Чтение и запись в раскрывающемся списке "Доступ" рядом с ним.
  3. Нажмите Сохранить изменения в нижней части страницы.
  4. Если вы установили приложение в своей учетной записи, проверьте свой почтовый ящик и перейдите по ссылке, чтобы принять новые разрешения. Каждый раз, когда вы изменяете разрешения или веб-перехватчики приложения, пользователи, которые установили приложение (включая вас самих), должны принять новые разрешения, прежде чем изменения вступят в силу. Чтобы принять новые разрешения, можно также перейти на страницу установки и щелкнуть "Настроить" рядом с приложением. В верхней части страницы появится баннер, сообщающий, что приложение запрашивает различные разрешения. Щелкните "Сведения" и нажмите "Принять новые разрешения".

Чтобы клонировать репозиторий с помощью разрешений приложения GitHub, можно использовать маркер установки приложения (x-access-token:<token>), показанный в следующем примере:

git clone https://x-access-token:@github.com//.git

Указанный код клонирует репозиторий по протоколу HTTP. Для него требуется полное имя репозитория, в том числе владелец репозитория (пользователь или организация) и имя репозитория. Например, репозиторий octocat Hello-World имеет полное имя octocat/hello-world.

После клонирования репозитория приложение должно извлечь последние изменения кода и извлечь определенную ссылку Git. Код, который должен все это сделать, будет хорошо вписываться в собственный метод. Для выполнения этих операций методу требуется имя и полное имя репозитория, а также ссылка для извлечения. Ссылка может быть SHA фиксации, ветвью или тегом. Добавьте следующий новый метод в раздел метода вспомогательного приложения в template_server.rb:

# Clones the repository to the current working directory, updates the
# contents using Git pull, and checks out the ref.
#
# full_repo_name  - The owner and repo. Ex: octocat/hello-world
# repository      - The repository name
# ref             - The branch, commit SHA, or tag to check out
def clone_repository(full_repo_name, repository, ref)
  @git = Git.clone("https://x-access-token:#{@installation_token.to_s}@github.com/#{full_repo_name}.git", repository)
  pwd = Dir.getwd()
  Dir.chdir(repository)
  @git.pull
  @git.checkout(ref)
  Dir.chdir(pwd)
end

Указанный код использует драгоценный камень ruby-git для клонирования репозитория с помощью маркера установки приложения. Этот код клонирует код в том же каталоге, что и template_server.rb. Чтобы выполнить команды Git в репозитории, код необходимо изменить в каталоге репозитория. Перед изменением каталогов код сохраняет текущую рабочую папку в переменной (pwd), чтобы помнить, куда вернуться перед выходом из метода clone_repository.

Из каталога репозитория этот код извлекает и объединяет последние изменения (@git.pull), извлекает ссылку (@git.checkout(ref)), а затем изменяет каталог обратно на исходную рабочую папку (pwd).

Теперь у вас есть метод, который клонирует репозиторий и извлекает ссылку. Далее необходимо добавить код, чтобы получить необходимые входные параметры и вызвать новый метод clone_repository. Добавьте следующий код в комментарий ***** RUN A CI TEST ***** в метод вспомогательного приложения initiate_check_run:

# ***** RUN A CI TEST *****
full_repo_name = @payload['repository']['full_name']
repository     = @payload['repository']['name']
head_sha       = @payload['check_run']['head_sha']

clone_repository(full_repo_name, repository, head_sha)

Указанный выше код получает полное имя репозитория и заголовок SHA фиксации из полезных данных веб-перехватчика check_run.

Шаг 2.3. Запуск RuboCop

Отлично! Вы клонируете репозиторий и создаете выполнения проверки с помощью сервера CI. Теперь вы перейдете к самым важным деталям анализатора кода RuboCop и заметок API проверок.

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

# Run RuboCop on all files in the repository
@report = `rubocop '#{repository}' --format json`
logger.debug @report
`rm -rf #{repository}`
@output = JSON.parse @report

Указанный код запускает RuboCop для всех файлов в каталоге репозитория. Параметр --format json — это удобный способ сохранения копии с результатами анализа кода в формате, который может проанализировать компьютер. Дополнительные сведения и пример формата JSON см. в документации RuboCop.

Так как этот код сохраняет результаты RuboCop в переменной @report, он может безопасно удалить извлечение репозитория. Этот код также анализирует JSON, чтобы можно было легко получить доступ к ключам и значениям в приложении GitHub с помощью переменной @output.

Примечание. Команду, используемую для удаления репозитория (rm -rf), невозможно отменить. См. Шаг 2.7. Советы по безопасности, чтобы узнать, как проверить веб-перехватчики на наличие внедренных вредоносных команд, которые можно использовать для удаления другого каталога, отличного от каталога, используемого приложением. Например, если злоумышленник отправил веб-перехватчик с именем репозитория ./, приложение удалит корневой каталог. 😱 Если по какой-либо причине вы не используете метод verify_webhook_signature (который включен в template_server.rb) для проверки отправителя веб-перехватчика, убедитесь, что имя репозитория является допустимым.

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

$ ruby template_server.rb

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

{
  "metadata": {
    "rubocop_version": "0.60.0",
    "ruby_engine": "ruby",
    "ruby_version": "2.3.7",
    "ruby_patchlevel": "456",
    "ruby_platform": "universal.x86_64-darwin18"
  },
  "files": [
    {
      "path": "Octocat-breeds/octocat.rb",
      "offenses": [
        {
          "severity": "convention",
          "message": "Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.",
          "cop_name": "Style/StringLiterals",
          "corrected": false,
          "location": {
            "start_line": 17,
            "start_column": 17,
            "last_line": 17,
            "last_column": 22,
            "length": 6,
            "line": 17,
            "column": 17
          }
        },
        {
          "severity": "convention",
          "message": "Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.",
          "cop_name": "Style/StringLiterals",
          "corrected": false,
          "location": {
            "start_line": 17,
            "start_column": 25,
            "last_line": 17,
            "last_column": 29,
            "length": 5,
            "line": 17,
            "column": 25
          }
        }
      ]
    }
  ],
  "summary": {
    "offense_count": 2,
    "target_file_count": 1,
    "inspected_file_count": 1
  }
}

Шаг 2.4. Сбор ошибок RuboCop

Переменная @output содержит проанализированные результаты JSON отчета RuboCop. Указанные результаты содержат раздел summary, который код может использовать для быстрого определения наличия ошибок. В указанном ниже коде задается вывод о выполнении проверки success при отсутствии сообщений об ошибках. RuboCop сообщает об ошибках для каждого файла в массиве files, поэтому при наличии ошибок необходимо извлечь некоторые данные из объекта файла.

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

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

При выполнении проверки ожидаются заметки в виде массива объектов. Каждый объект заметки должен включать path, start_line, end_line, annotation_level и message. RuboCop также предоставляет start_column и end_column, позволяя включить эти необязательные параметры в заметку. Заметки поддерживают только start_column и end_column в одной строке. Дополнительные сведения см. в annotations справочной документации по объекту.

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

annotations = []
# You can create a maximum of 50 annotations per request to the Checks
# API. To add more than 50 annotations, use the "Update a check run" API
# endpoint. This example code limits the number of annotations to 50.
# See /rest/reference/checks#update-a-check-run
# for details.
max_annotations = 50

# RuboCop reports the number of errors found in "offense_count"
if @output['summary']['offense_count'] == 0
  conclusion = 'success'
else
  conclusion = 'neutral'
  @output['files'].each do |file|

    # Only parse offenses for files in this app's repository
    file_path = file['path'].gsub(/#{repository}\//,'')
    annotation_level = 'notice'

    # Parse each offense to get details and location
    file['offenses'].each do |offense|
      # Limit the number of annotations to 50
      next if max_annotations == 0
      max_annotations -= 1

      start_line   = offense['location']['start_line']
      end_line     = offense['location']['last_line']
      start_column = offense['location']['start_column']
      end_column   = offense['location']['last_column']
      message      = offense['message']

      # Create a new annotation for each error
      annotation = {
        path: file_path,
        start_line: start_line,
        end_line: end_line,
        start_column: start_column,
        end_column: end_column,
        annotation_level: annotation_level,
        message: message
      }
      # Annotations only support start and end columns on the same line
      if start_line == end_line
        annotation.merge({start_column: start_column, end_column: end_column})
      end

      annotations.push(annotation)
    end
  end
end

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

Если значение offense_count равно нулю, тест CI имеет значение success. При наличии ошибок этот код задает для заключения значение neutral, чтобы предотвратить строгое применение ошибок из анализатора кода. Но значение заключения можно изменить на failure, если необходимо убедиться, что набор проверок завершается ошибкой при возникновении ошибок анализа кода.

При обнаружении ошибок указанный код выполняет итерацию по массиву files в отчете RuboCop. Для каждого файла он извлекает путь к файлу и задает значение notice для уровня заметки. Вы можете пойти еще дальше и задать определенные пороги предупреждений для каждого типа RuboCop Cop, но чтобы упростить работу в этом кратком руководстве, для всех ошибок задается уровень notice.

Этот код также выполняет итерацию по каждой ошибке в массиве offenses и собирает расположение нарушения и сообщения об ошибке. После извлечения необходимых сведений код создает заметку для каждой ошибки и сохраняет ее в массиве annotations. Так как заметки поддерживают только начальные и конечные столбцы в одной строке, start_column и end_column добавляются в объект annotation только в том случае, если значения начальной и конечной строк совпадают.

Этот код еще не создает заметку для выполнения проверки. Вы добавите этот код в следующем разделе.

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

Каждое выполнение проверки из GitHub содержит объект output, включающий title, summary, text, annotations и images. summary и title являются единственными обязательными параметрами для output, но только они не предоставляют много сведений, поэтому в этом кратком руководстве также добавляются text и annotations. Код здесь не добавляет изображение, но вы можете добавить его, если хотите!

Для summary в этом примере используются сводные сведения из RuboCop и добавляются некоторые новые строки (\n) для форматирования выходных данных. Вы можете настроить то, что вы добавляете в параметр text, но в этом примере для параметра text устанавливается версия RuboCop. Чтобы задать summary и text, добавьте этот код к коду, добавленный в предыдущем разделе:

# Updated check run summary and text parameters
summary = "Octo RuboCop summary\n-Offense count: #{@output['summary']['offense_count']}\n-File count: #{@output['summary']['target_file_count']}\n-Target file count: #{@output['summary']['inspected_file_count']}"
text = "Octo RuboCop version: #{@output['metadata']['rubocop_version']}"

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

# Mark the check run as complete!
@installation_client.update_check_run(
  @payload['repository']['full_name'],
  @payload['check_run']['id'],
  status: 'completed',
  conclusion: 'success',
  accept: 'application/vnd.github+json'
)

Вам потребуется обновить этот код, чтобы использовать переменную conclusion, заданную на основе результатов RuboCop (в success или neutral). Код можно обновить следующим образом:

# Mark the check run as complete! And if there are warnings, share them.
@installation_client.update_check_run(
  @payload['repository']['full_name'],
  @payload['check_run']['id'],
  status: 'completed',
  conclusion: conclusion,
  output: {
    title: 'Octo RuboCop',
    summary: summary,
    text: text,
    annotations: annotations
  },
  actions: [{
    label: 'Fix this',
    description: 'Automatically fix all linter notices.',
    identifier: 'fix_rubocop_notices'
  }],
  accept: 'application/vnd.github+json'
)

Теперь, когда вы задали заключение, используя состояние теста CI, и добавили выходные данные из результатов RuboCop, создан тест CI! Поздравляем. 🙌

Указанный код также добавляет на сервер CI возможность запрошенных действий через объект actions. Запрошенные действия добавляют кнопку на вкладке Проверки в GitHub, которая позволяет пользователю запрашивать выполнение проверки для выполнения дополнительных действий. Дополнительное действие полностью настраивается приложением. Например, так как RuboCop имеет возможность автоматически исправлять ошибки, обнаруженные в коде Ruby, сервер CI может использовать кнопку запрошенных действий, чтобы разрешить пользователям запрашивать автоматические исправления ошибок. Когда кто-то нажимает кнопку, приложение получает событие check_run с действием requested_action. Каждое запрошенное действие имеет identifier, используемый приложением для определения нажатия кнопки.

Указанный код не содержит ошибки, которые еще не исправляются автоматически с помощью RuboCop. Это будет добавлено в следующем разделе. Но сначала ознакомьтесь с тестом CI, который вы только что создали, запустив сервер template_server.rb еще раз и создав новый запрос на вытягивание:

$ ruby template_server.rb

Заметки будут отображаться на вкладке Проверки.

Заметки выполнения проверки на вкладке "Проверки"

Обратите внимание на кнопку "Исправить это", созданную путем добавления запрошенного действия.

Кнопка для запрошенного действия выполнения проверки

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

Заметки выполнения проверки на вкладке "Измененные файлы"

Шаг 2.6. Автоматическое исправление ошибок RuboCop

Если вы дошли к этому месту, поздравляем! 👏 Вы уже создали тест CI. В этом разделе вы добавите еще одну возможность, которая использует RuboCop для автоматического исправления обнаруженных ошибок. Вы уже добавили кнопку "Исправить это" в предыдущем разделе. Теперь вы добавите код для обработки события выполнения проверки requested_action, активируемого при нажатии кнопки "Исправить это".

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

Для отправки в репозиторий приложение должно иметь разрешения на запись для содержимого репозитория. Вы задали это разрешение на чтение и запись еще в разделе Шаг 2.2. Клонирование репозитория, поэтому все готово.

Чтобы зафиксировать файлы, Git должен знать имя пользователя и адрес электронной почты, которые следует связать с фиксацией. Добавьте еще две переменные среды в файл .env для хранения параметров имени (GITHUB_APP_USER_NAME) и электронной почты (GITHUB_APP_USER_EMAIL). Ваше имя может быть именем приложения, а адрес электронной почты может быть любым адресом для этого примера. Пример:

GITHUB_APP_USER_NAME=Octoapp
GITHUB_APP_USER_EMAIL=octoapp@octo-org.com

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

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

В разделе Шаг 1.4. Обновление выполнения проверки вы обновили event_handler для обработки действий в событии check_run. У вас уже есть инструкция CASE для обработки типов действий created и rerequested:

when 'check_run'
  # Check that the event is being sent to this app
  if @payload['check_run']['app']['id'].to_s === APP_IDENTIFIER
    case @payload['action']
    when 'created'
      initiate_check_run
    when 'rerequested'
      create_check_run
  end
end

Добавьте еще одну инструкцию when после CASE rerequested для обработки события rerequested_action:

when 'requested_action'
  take_requested_action

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

# Handles the check run `requested_action` event
# See /webhooks/event-payloads/#check_run
def take_requested_action
  full_repo_name = @payload['repository']['full_name']
  repository     = @payload['repository']['name']
  head_branch    = @payload['check_run']['check_suite']['head_branch']

  if (@payload['requested_action']['identifier'] == 'fix_rubocop_notices')
    clone_repository(full_repo_name, repository, head_branch)

    # Sets your commit username and email address
    @git.config('user.name', ENV['GITHUB_APP_USER_NAME'])
    @git.config('user.email', ENV['GITHUB_APP_USER_EMAIL'])

    # Automatically correct RuboCop style errors
    @report = `rubocop '#{repository}/*' --format json --auto-correct`

    pwd = Dir.getwd()
    Dir.chdir(repository)
    begin
      @git.commit_all('Automatically fix Octo RuboCop notices.')
      @git.push("https://x-access-token:#{@installation_token.to_s}@github.com/#{full_repo_name}.git", head_branch)
    rescue
      # Nothing to commit!
      puts 'Nothing to commit'
    end
    Dir.chdir(pwd)
    `rm -rf '#{repository}'`
  end
end

Указанный код клонирует репозиторий так же, как и код, добавленный в разделе Шаг 2.2. Клонирование репозитория. Инструкция if проверяет, соответствует ли идентификатор запрошенного действия идентификатору кнопки RuboCop (fix_rubocop_notices). Когда они совпадают, код клонирует репозиторий, задает имя пользователя и адрес электронной почты Git, а затем запускает RuboCop с параметром --auto-correct. Параметр --auto-correct автоматически применяет изменения к файлам локального сервера CI.

Файлы изменяются локально, но вам по-прежнему потребуется отправить их в GitHub. Вы будете использовать удобный драгоценный камень ruby-git снова, чтобы зафиксировать все файлы. В Git есть одна команда, которая выполняет этапы всех измененных или удаленных файлов и фиксирует их: git commit -a. Чтобы сделать то же самое с помощью ruby-git, указанный код использует метод commit_all. Затем код отправляет зафиксированные файлы в GitHub с помощью маркера установки, используя тот же способ проверки подлинности, что и команда Git clone. Наконец, он удаляет каталог репозитория, чтобы убедиться, что рабочая папка подготовлена к следующему событию.

Вот и все! Написанный код теперь завершает сервер CI API проверок. 💪 Перезапустите сервер template_server.rb еще раз и создайте новый запрос на вытягивание:

$ ruby template_server.rb

Примечание. Прежде чем тестировать изменения, необходимо перезапустить сервер Sinatra. Введите Ctrl-C, чтобы остановить сервер, а затем снова выполните ruby template_server.rb. Если вы не хотите делать это при каждом изменении в коде приложения, можно использовать перезагрузку.

На этот раз нажмите кнопку "Исправить это", чтобы автоматически исправить ошибки RuboCop, обнаруженные на вкладке Проверки.

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

Новая фиксация для автоматического исправления уведомлений Octo RuboCop

Так как новая фиксация была отправлена в репозиторий, на вкладке Проверки появится новый набор проверок для Octo RuboCop. Но на этот раз ошибок нет, так как RuboCop все их исправил. 🎉

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

Полный код для приложения, который вы только что создали в файле server.rb, можно найти в репозитории Создание тестов CI с помощью API проверок.

Шаг 2.7. Советы по безопасности

Код приложения GitHub шаблона уже содержит метод проверки входящих полезных данных веб-перехватчика, чтобы убедиться, что они получены из надежного источника. Если вы не проверяете полезные данные веб-перехватчика, необходимо убедиться, что при включении имен репозитория в полезные данные веб-перехватчика он не содержит произвольных команд, которые могут использоваться во вредоносных целях. Указанный ниже код проверяет, содержит ли имя репозитория только латинские буквы, дефисы и символы подчеркивания. Чтобы предоставить полный пример, полный код server.rb, доступный во вспомогательном репозитории для этого краткого руководства, включает как метод проверки входящих полезных данных веб-перехватчика, так и эту проверку имени репозитория.

# This quickstart example uses the repository name in the webhook with
# command-line utilities. For security reasons, you should validate the
# repository name to ensure that a bad actor isn't attempting to execute
# arbitrary commands or inject false repository names. If a repository name
# is provided in the webhook, validate that it consists only of latin
# alphabetic characters, `-`, and `_`.
unless @payload['repository'].nil?
  halt 400 if (@payload['repository']['name'] =~ /[0-9A-Za-z\-\_]+/).nil?
end

Устранение неполадок

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

  • Вопрос. Мое приложение не отправляет код в GitHub. Я не вижу исправлений, которые RuboCop выполняет автоматически!

    Ответ. Убедитесь, что у вас есть разрешения на чтение и запись для содержимого репозитория и что выполняется клонирование репозитория с маркером установки. Дополнительные сведения см. в разделе Шаг 2.2. Клонирование репозитория.

  • Вопрос. В выходных данных отладки template_server.rb отображается ошибка, связанная с клонированием репозитория.

    Ответ. Если вы видите следующую ошибку, вы не удалили извлечение репозитория в методах initiate_check_run или take_requested_action:

    2018-11-26 16:55:13 - Git::GitExecuteError - git  clone '--' 'https://x-access-token:ghs_9b2080277016f797074c4dEbD350745f4257@github.com/codertocat/octocat-breeds.git' 'Octocat-breeds'  2>&1:fatal: destination path 'Octocat-breeds' already exists and is not an empty directory.:

    Сравните код с файлом server.rb, чтобы убедиться, что у вас есть тот же код и методы initiate_check_run и take_requested_action.

  • Вопрос. Новые выполнения проверки не отображаются на вкладке "Проверки" в GitHub.

    Ответ. Перезапустите Smee и повторно запустите сервер template_server.rb.

  • Вопрос. Кнопка "Повторно запустить все" на вкладке "Проверки" в GitHub не отображается.

    Ответ. Перезапустите Smee и повторно запустите сервер template_server.rb.

Заключение

Изучив это руководство, вы ознакомились с основами использования API проверок для создания сервера CI! Для этого вы:

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

Дальнейшие действия

Ниже приведены некоторые идеи о том, что еще можно сделать:

  • На данный момент кнопка "Исправить это" всегда отображается. Обновите код, написанный для отображения кнопки "Исправить это", только если RuboCop обнаруживает ошибки.
  • Если вы предпочитаете, чтобы файлы не фиксировались RuboCop непосредственно в головной ветви, можно обновить код, чтобы создать запрос на вытягивание с новой ветвью на основе головной ветви.