Git
Chapters ▾ 2nd Edition

6.5 GitHub - Автоматизиране с GitHub

Автоматизиране с GitHub

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

За щастие, GitHub е доста гъвкав в това отношение. Тук ще разгледаме как се ползват hooks системата и API-то на GitHub.

Услуги и Hooks

Hooks and Services секцията в административната част на хранилище в GitHub е най-лесния начин да накарате GitHub да комуникира с външни системи.

Services

Ще разгледаме първо Services. И Hooks и Services интеграциите могат да се намерят в Settings секцията на вашето хранилище, където преди гледахме при добавяне на сътрудници и смяна на клона по подразбиране за хранилището. В секцията “Webhooks and Services” ще видите нещо подобно на Services and Hooks конфигурационна секция..

Services and hooks
Figure 130. Services and Hooks конфигурационна секция.

Може да избирате от десетки услуги, повечето от тях предлагащи интеграция с други комерсиални или open source системи. Сред тях са Continuous Integration услуги, услуги за проследяване на проблеми и грешки, chat room системи и системи за документация. Нека разгледаме настройката на една от най-простите, Email hook. Изберете “email” от падащия списък “Add Service” и ще попаднете на екран подобен на Email service конфигурация..

Email service
Figure 131. Email service конфигурация.

В този случай, ако натиснете “Add service” бутона, имейл адресът който укажете ще получава съобщение всеки път, когато някой публикува код в хранилището. Услугите могат да слушат за много различни типове събития, но повечето от тях случат само за push събития и предприемат съответните действия с данните.

Ако ползвате система, която искате да интегрирате с GitHub, трябва да проверите тук дали не съществува налична интеграционна услуга. Например, ако ползвате Jenkins за тестване на код, можете да разрешите вградената Jenkins интеграция за да пуснете автоматично тест всеки път когато някой публикува код в хранилището ви.

Hooks

Ако ви трябва нещо по-специфично или желаете да интегрирате с услуга/сайт, които не присъстват в списъка на GitHub, можете да използвате по-общата hooks система. Hooks функционалността на GitHub е доста опростена. Указвате URL и GitHub ще изпрати HTTP заявка към него при всяко желано от вас събитие.

В общи линии, можете да пуснете малка уеб услуга, която да следи за hook-заявките от GitHub и да прави нещо с получените данни.

За да разрешите hook, натиснете “Add webhook” бутона в Services and Hooks конфигурационна секция.. Ще видите страница подобна на Web hook конфигурация..

Web hook
Figure 132. Web hook конфигурация.

Конфигурацията е много опростена. В повечето случаи просто въвеждате URL и секретен ключ и натискате “Add webhook”. Има доста опции за това при кои събития искате GitHub да ви изпраща данни — по подразбиране това се случва само при push събития, когато някой публикува промени в произволен клон от хранилището.

Нека видим малък пример за уеб услуга, която бихте могли да напишете за обслужване на данните от web hook. Ще използваме уеб framework системата Sinatra за Ruby, понеже тя е сравнително компактна и би следвало лесно да разберете какво вършим.

Нека приемем, че искаме да получаваме поща, ако специфичен потребител публикува код в конкретен клон и промени конкретен файл. Можем сравнително лесно да го направим така:

require 'sinatra'
require 'json'
require 'mail'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON

  # gather the data we're looking for
  pusher = push["pusher"]["name"]
  branch = push["ref"]

  # get a list of all the files touched
  files = push["commits"].map do |commit|
    commit['added'] + commit['modified'] + commit['removed']
  end
  files = files.flatten.uniq

  # check for our criteria
  if pusher == 'schacon' &&
     branch == 'ref/heads/special-branch' &&
     files.include?('special-file.txt')

    Mail.deliver do
      from     'tchacon@example.com'
      to       'tchacon@example.com'
      subject  'Scott Changed the File'
      body     "ALARM"
    end
  end
end

Тук прочитаме JSON данните от GitHub и търсим кой е направил публикуването, в кой клон и кои файлове са били модифицирани във всички публикувани къмити. След това проверяваме информацията според нашия критерий и изпращаме имейл, ако срещнем съвпадение.

За да разработите и тествате нещо от този род, разполагате с удобна developer конзола на същия екран, в който настройвате вашия hook. Можете да видите последните няколко съобщения, които GitHub се е опитал да направи за този webhook. За всеки hook може да видите в детайли кога е бил изпратен, дали изпращането е успешно, както и тялото и хедърите за заявката и отговора при операцията. Това много улеснява тестването и дебъгването на вашите hooks.

Webhook debug
Figure 133. Web hook debugging данни.

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

За повече информация как да пишете webhooks и за всички възможни типове GitHub събития, погледнете документацията за разработчици на GitHub на адрес https://developer.github.com/webhooks/

GitHub API

Services and hooks функционалността ви дава инструменти за получаване на push нотификация за събитията, които се случват във вашите хранилища, но какво да правите, ако искате повече информация за съответните събития? Например, бихте искали да автоматизирате неща като добавянето на сътрудници или маркирането на issues.

Тук е мястото да се възползвате от GitHub API. GitHub има голямо количество API endpoints позволяващи да правите почти всичко, което можете да правите в сайта, но по автоматизиран начин. В тази част ще видим как да се автентикираме и да се свържем с API интерфейса, как да коментираме по issue и как да променим статуса на Pull Request през API.

Основни действия

Най-простото нещо, което може да направите е да изпратите проста GET заявка към endpoint, който не изисква автентикация. Това може да е потребителска или read-only информация за open source проект. Например, ако искаме да знаем повече за потебителя “schacon”, можем да изпълним нещо такова:

$ curl https://api.github.com/users/schacon
{
  "login": "schacon",
  "id": 70,
  "avatar_url": "https://avatars.githubusercontent.com/u/70",
# …
  "name": "Scott Chacon",
  "company": "GitHub",
  "following": 19,
  "created_at": "2008-01-27T17:19:28Z",
  "updated_at": "2014-06-10T02:37:23Z"
}

Има безброй подобни endpoints предоставящи информация за организации, проекти, issues, къмити — почти за всичко, което можете да видите публично в GitHub. Можете дори да използвате API за рендериране на специален Markdown или за да намерите .gitignore шаблон.

$ curl https://api.github.com/gitignore/templates/Java
{
  "name": "Java",
  "source": "*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}

Коментар по Issue

Обаче, ако искате да направите определено действие в сайта, като коментар по Issue или Pull Request, или искате да погледнете или комуникирате с частно съдържание, ще се наложи да се автентикирате.

Съществуват няколко начина за това. Можете да ползвате базова автентикация с име и парола, но по-добра идея е да ползвате персонален token за достъп. Можете да го генерирате в секцията “Applications” на страницата с настройки.

Access Token
Figure 134. Генерирайте token за достъп в “Applications” секцията от страницата с настройки.

Ще бъдете попитани за обхвата на token-а и за кратко описание. Уверете се, че използвате добро описание, така че да сте спокойни по-късно, когато изтривате token-а след като вече не се нуждаете от него.

GitHub ще ви покаже token-а само веднъж, така че се уверете, че сте го копирали. Можете вече да го използвате за автентикация вместо име и парола. Това е чудесно, защото можете да ограничите обхвата на това, което желаете да манипулирате и също така, token-ът може да се отмени.

Получавате и допълнително предимство. Без автентикация, можете да правите до 60 заявки на час. Ако се автентикирате, броят им нараства до 5,000 на час.

Нека го използваме за да пуснем коментар по един от нашите Issues. Ще коментираме Issue #6. За да направим това, изпращаме HTTP POST заявка към repos/<user>/<repo>/issues/<num>/comments с token-а, който току що генерирахме като Authorization хедър.

$ curl -H "Content-Type: application/json" \
       -H "Authorization: token TOKEN" \
       --data '{"body":"A new comment, :+1:"}' \
       https://api.github.com/repos/schacon/blink/issues/6/comments
{
  "id": 58322100,
  "html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
  ...
  "user": {
    "login": "tonychacon",
    "id": 7874698,
    "avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
    "type": "User",
  },
  "created_at": "2014-10-08T07:48:19Z",
  "updated_at": "2014-10-08T07:48:19Z",
  "body": "A new comment, :+1:"
}

Сега, ако отидем в този issue, можем да видим коментара ни там, както е показано в Коментар изпратен с GitHub API..

API коментар
Figure 135. Коментар изпратен с GitHub API.

Може да ползвате API интерфейса за да правите почти всичко, което правите и през сайта — създаване и настройка на milestones, асоцииране на хора към Issues и Pull Request-и, създаване и промяна на етикети, достъп до данните на къмит, създаване на нови къмити и клонове, отваряне, затваряне и сливане на Pull Request-и, създаване и редакция на екипи, коментари по редове на код в Pull Request, търсене в сайта и т.н.

Промяна на статуса на Pull Request

Разглеждаме последния пример, понеже е наистина полезен, ако работите с Pull Request-и. Всеки къмит може да има един или повече статуси асоциирани с него и разполагате с API за добавяне и запитване към статус.

Повечето Continuous Integration и testing услуги използват този API за да реагират на публикувания тествайки кода, който е бил пратен и след това рапортувайки дали конкретния къмит е преминал всички тестове. Можете също да ползвате това за проверка дали къмит съобщенията са коректно форматирани, дали изпратилия къмита е следвал указанията ви за сътрудничество в проекта, дали къмитът е с валиден подпис — и безброй други неща.

Да приемем, че сте създали webhook във ваше хранилище, който се свързва с малка уеб услуга, която проверява за стринга Signed-off-by в къмит съобщението.

require 'httparty'
require 'sinatra'
require 'json'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON
  repo_name = push['repository']['full_name']

  # look through each commit message
  push["commits"].each do |commit|

    # look for a Signed-off-by string
    if /Signed-off-by/.match commit['message']
      state = 'success'
      description = 'Successfully signed off!'
    else
      state = 'failure'
      description = 'No signoff found.'
    end

    # post status to GitHub
    sha = commit["id"]
    status_url = "https://api.github.com/repos/#{repo_name}/statuses/#{sha}"

    status = {
      "state"       => state,
      "description" => description,
      "target_url"  => "http://example.com/how-to-signoff",
      "context"     => "validate/signoff"
    }
    HTTParty.post(status_url,
      :body => status.to_json,
      :headers => {
        'Content-Type'  => 'application/json',
        'User-Agent'    => 'tonychacon/signoff',
        'Authorization' => "token #{ENV['TOKEN']}" }
    )
  end
end

Надяваме се, че кодът е лесно проследим. Преглеждаме всеки изпратен къмит, търсим за стринга Signed-off-by в къмит съобщението и накрая изпращаме HTTP POST заявка към /repos/<user>/<repo>/statuses/<commit_sha> API endpoint-а със съответния статус.

В този случай, можете да изпратите статус (success, failure, error), за описание на това какво се е случило, URL адрес за повече информация и “context” в случай, че има няколко статуса за единичен къмит. Например, една testing услуга може да предостави статус и една валидизираща услуга също може да предостави статус — “context” полето е това, което ги диференцира.

Ако някой отвори нов Pull Request в GitHub и този hook е бил настроен, може да видите нещо като Commit status през API..

Commit status
Figure 136. Commit status през API.

Сега може да видите малка зелена отметка до къмита, който има стринга “Signed-off-by” в съобщението си и червено кръстче до този, който авторът е забравил да подпише. Може да видите също, че Pull Request-ът приема статуса на последния къмит в клона и ви предупреждава, ако резултатът е грешка. Това е наистина удобно, ако ползвате това API за тестове, така че да не слеете без да искате някой къмит, който не е минал през теста успешно.

Octokit

Въпреки, че правим всичко през curl и прости HTTP заявки в нашите примери, налични са няколко open-source библиотеки, които могат да ви помогнат да ползвате API интерфейса в по-идиоматичен стил. По време на писането на книгата, поддържаните езици включваха Go, Objective-C, Ruby, и .NET. Проверете https://github.com/octokit за повече информация, понеже те поемат повечето HTTP действия вместо вас.

Надяваме се, че тези инструменти ще ви помогнат да настроите поведението на GitHub така, че да комуникира с вашите системи и работни похвати така като желаете. За пълна документация на целия API интерфейс, както и за упътвания за често извършвани задачи, посетете https://developer.github.com.