Анализ истории бессерверного репозитория git

Я только что опубликовал свой пример проекта, демонстрирующий, как легко выполнять автоматическую проверку кода с помощью Github API.

Он основан на другом посте, который я написал некоторое время назад.

В этом конкретном примере я анализирую историю проекта в поисках «горячих точек».

Вы можете найти введение в ПРОЧТИ МЕНЯ но резюмирую коротко:

Горячие точки — это файлы, которые наиболее часто редактируются в истории проекта.

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

Анализ истории изменений в проекте может привести к гораздо более интересным открытиям, чем просто статический анализ исходного кода.
Эта тема называется «криминалистика кода», и подробнее о ней можно прочитать в замечательной книге Ваш код как место преступления by Adam Tornhill.

В этом посте я хотел бы больше сосредоточиться на объяснении кода и конфигурации.

Веб-хук Github

Во-первых, что такое вебхук Github и как его настроить.
Короче говоря, это HTTP-запрос, который Gihub вызывает для предварительно заданного URL-адреса при определенных действиях, например, при создании или редактировании запроса на извлечение.

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

Конфигурация вебхука

Для настройки необходима конечная точка, которую мы разработаем с помощью Serverless Framework и AWS API Gateway + Lambda, а также случайный токен под названием «Секрет».

Создание вебхука

Мы можем сгенерировать секрет, например, используя ruby ​​в оболочке:

ruby -rsecurerandom -e 'puts SecureRandom.hex(20)'

Как только мы разработаем сервис, мы обновим URL.

Конечная точка веб-перехватчика.

Мы можем создать Java-приложение с Serverless Framework, используя:

sls create --path webhook-service --name webhook-service --template aws-java-gradle

Он будет генерировать источники в папке webhook-service.
По умолчанию служба будет называться «hello», которую мы, возможно, предпочли бы назвать по-другому. Мы можем обновить его в двух местах:

  // set the base name of the zip file
    baseName = "hello"

package:
  artifact: build/distributions/hello.zip

Пакет больше не будет называться hello.zip если бы мы обновили build.gradle с разными baseName.

Далее нам нужно настроить две лямбда-функции в serverless.yaml и разрешить Lambda вызывать другую функцию.

Файл будет выглядеть следующим образом:

service: webhook-service

provider:
  name: aws
  runtime: java8
  region: us-east-1
  // configuring permissions to invoke one lambda from another
  iamRoleStatements:
  - Effect: Allow
    Action:
    - lambda:InvokeFunction
    Resource: "*"

package:
  artifact: build/distributions/webhook-service.zip

functions:
  webhook:
    handler: com.serverless.ApiGatewayHandler
    timeout: 30 
    events:
    - http:
        path: webhook
        method: post
        cors: true
  job:
    handler: com.serverless.Job
    timeout: 900 

Я дал максимально возможные тайм-ауты для функций.

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

Затем мы переместим реализацию во вторую функцию (называемую «job»), а в первой (называемой «webhook») мы будем вызывать только вторую функцию асинхронно, используя AWS JDK.

Вот логика обработки вебхука:

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

Map<String, Object> headers = (Map<String, Object>) input.get("headers");
String sig = (String) headers.get("X-Hub-Signature");
String githubEvent = (String) headers.get("X-GitHub-Event");
String id = (String) headers.get("X-GitHub-Delivery");

validate(notEmpty(sig), "No X-Hub-Signature found on request");
validate(notEmpty(githubEvent), "No X-Github-Event found on request");
validate(notEmpty(id), "No X-Github-Delivery found on request");

Затем возьмите подпись и сравните с рассчитанным нами значением:

 String calculatedSig = "sha1=" + calculateRFC2104HMAC(body, WEB_HOOK_TOKEN);
 validate(sig.equals(calculatedSig), "X-Hub-Signature incorrect. Github webhook webHookToken doesn't match");

Если это не соответствует, мы будем генерировать исключение.

Алгоритм вычисления подписи прост, и мы используем только стандартные классы Java:


import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

...
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private static final char[] hexCode = "0123456789abcdef".toCharArray();

    public static String calculateRFC2104HMAC(String data, String key)
        throws NoSuchAlgorithmException, InvalidKeyException {

        SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
        Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
        mac.init(signingKey);
        return printHexBinary(mac.doFinal(data.getBytes()));
    }

    private static String printHexBinary(byte[] data) {
        StringBuilder r = new StringBuilder(data.length * 2);
        for (byte b : data) {
            r.append(hexCode[(b >> 4) & 0xF]);
            r.append(hexCode[(b & 0xF)]);
        }
        return r.toString();
    }

Затем мы можем извлечь тело из запроса веб-перехватчика.

String body = (String) input.get("body");
PushEvent pushEvent = OBJECT_MAPPER.readValue(body, PushEvent.class);

Для этой цели я использую библиотеку Джексона для десериализации строки JSON в мой Java-бин. PushEvent.

Нам нужны только следующие данные из запроса:

  • ref — название ветки, например:
"refs/heads/test-1"
  • репозиторий.имя — имя репозитория
  • репозиторий.url — URL-адрес репозитория, например:
"
  • репозиторий.owner.name — имя пользователя github
  • сравнение — URL-адрес сравнения, например:
"

Во-первых, нам нужно клонировать репозиторий во временную папку Lambda. Для этого нам нужно ref а также repository.name.

Затем мы просматриваем историю git с самого начала, чтобы найти список 10 наиболее часто изменяемых файлов с количеством их модификаций.

Затем мы берем список файлов, отредактированных между коммитами в compare url, поэтому мы должны извлечь из него хэши. Мы получим такие значения, как: bd31aff3fd8c^ а также 53b54347ec75который мы можем использовать, чтобы сделать diff.

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

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

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

Команды curl для упомянутых Git API будут выглядеть так:

curl -X GET -H 'Authorization: token {personalApiToken}' \
'
curl - X POST - H 'Authorization: token {personalApiToken}' \
 \ -d '{"event" :"COMMENT", "body" : "{reviewContent}"}'

Я использую облегченный клиент REST (Он был един), чтобы сделать эти звонки.

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

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

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

Похожие записи

Добавить комментарий

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