Git
Chapters ▾ 2nd Edition

6.5 GitHub - GitHub Scripten

GitHub Scripten

We hebben nu alle hoofdfuncties en workflows van GitHub hebben behandeld, maar elke grote groep of project zal aanpassingen hebben die ze willen maken of services van buitenaf die ze willen integreren.

Gelukkig voor ons is GitHub echt op vele manieren redelijk hackbaar. In deze paragraaf zullen we behandelen hoe het zgn. GitHub haken (hooks) en API systeem te gebruiken om GitHub zich te laten gedragen zoals we willen.

Hooks

Het Hooks en Services deel van het GitHub repository beheer is de eenvoudigste manier om GitHub te laten samenwerken met externe systemen.

Services

Eerst zullen we naar Services kijken. Zowel Hooks als Services integratie kunnen in het Settings gedeelte van je repository gevonden worden, waar we eerder naar gekeken hebben bij het toevoegen van medewerkers en het wijzigen van de standaard branch van je project. Onder de “Webhooks and Services” tab zul je iets als Services and Hooks configuratie deel. zien.

Services en hooks
Figure 130. Services and Hooks configuratie deel.

Er zijn tientallen services waar je uit kunt kiezen, de meeste zijn integraties naar andere commerciele en open source systemen. De meeste daarvan zijn Continuous Integration services, bug en issue trackers, chat room systemen en documentatie systemen. We zullen je door het opzetten van een eenvoudige leiden: de email-hook. Als je “email kiest uit de ``Add Service” dropdown, krijg je een configuratie scherm zoals Email service configuratie..

Email service
Figure 131. Email service configuratie.

In dit geval, als we de “Add service” knop klikken, zal het email adres die we intypen elke keer een bericht ontvangen als iemand naar de repository pusht. Services kunnen luisteren naar verschillende type gebeurtenissen, maar de emesten luisteren alleen naar push events en doen dan iets met die gegevens.

Als er een systeem is dat je gebruikt en die je wilt integreren met GitHub, zou je hier moeten kijken om te zien of er een bestaande service integratie beschikbaar is. Je zou, als je bijvoorbeeld Jenkins gebruikt om tests te draaien op je codebase, de ingebouwde Jenkins service integratie kunnen aanzetten om een testrun af te trappen elke keer als iemand naar jouw repository pusht.

Hooks

Als je iets meer specifieker nodig hebt, of je wilt een service of site integreren die niet in de lijst staat, kan je in plaats daarvan het meer generieke hooks systeem gebruiken. GitHub repository hooks zijn redelijk eenvoudig. Je geeft een URL op en GitHub zal een HTTP payload posten op die URL bij elke gebeurtenis dat je maar wilt.

Hoe dit in het algemeen werkt is dat je een kleine web service kunt opzetten die naar een GitHub hook payload luistert en dan iets met de gegevens doet als het is ontvangen.

Om een hook aan te zetten, klik je de “Add webhook” knop in Services and Hooks configuratie deel.. Dit leidt je naar een pagina die eruit ziet als Web hook configuratie..

Web hook
Figure 132. Web hook configuratie.

De configuratie van een web hook is redelijk eenvoudig. In de meeste gevallen voer je een URL in en een geheime sleutel en klikt “Add webhook”. Er zijn een paar opties voor welke gebeurtenissen je wilt waarvor GitHub je een payload stuurt — standaard is om alleen een payload te ontvangen voor de push gebeurtenis, als iemand nieuwe code naar een van de branches uit je repository pusht.

Laten we een kort voorbeeld van een web service bekijken die je zou kunnen opzetten om een web hook te verwerken. We zullen het Ruby web framework Sinatra gebruiken omdat dit redelijk bondig is en je in staat zou moeten zijn om snel te zien wat we aan het doen zijn.

Laten we stellen dat we een email willen ontvangen als een bepaald persoon naar een specifieke branch van ons project pusht waarin een zeker bestand wordt gewijzigd. We kunnen dat relatief eenvoudig doen met code zoals deze:

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

Hier nemen we de JSON payload die GitHub ons levert en kijken na wie gepushed heeft, naar welke branch deze gepushed heeft en welke bestanden geraakt zijn in alle commits die zijn gepusht. Dan houden we die gegevens tegen onze criteria en sturen een email als ze passen.

Om zoiets te kunnen ontwikkelen en testen, heb je een nette ontwikkelaarsscherm in hetzelfde scherm waar je ook de hook ingesteld hebt. Je kunt de laatste paar leveranties die GitHub heeft proberen te maken voor die webhook zien. Voor elke hook kan je uitvinden wanneer het was afgeleverd, of dit succesvol was en de body en headers voor zowel de vraag en het antwoord. Dit maakt het ongelovelijk eenvoudig om je hooks te testen en te debuggen.

Webhook debug
Figure 133. Web hook debug informatie.

De andere geweldige mogelijkheid van dit is dat je elk van de payloads opnieuw kan laten afleveren om je service makkelijk te testen.

Voor meer informatie over hoe webhooks te schrijven en alle verschillende type gebeurtenissen waar je naar kunt verwijzen we je naar de GitHub Developer documentatie op: https://developer.github.com/webhooks/

De GitHub API

Services en hooks bieden je een manier om push berichten te ontvangen van gebeurtenissen die plaatsvinden op je repositories, maar wat nu als je meer informatie hierover nodig hebt? Wat als je iets wilt automatiseren zoals medewerkers toevoegen of issues markeren?

Dit is waar de GitHub API handig bij gebruikt kan worden. GitHub heeft ongelofelijk veel API endpoints om bijna alles wat je op de website kan doen op een geautomatiseerde manier kan doen. In deze paragraaf zullen we leren hoe te authenticeren en te verbinden met de API, hoe te reageren op een issue en hoe de status van een Pull Request te wijzigen middels de API.

Eenvoudig gebruik

Het meest basale wat je kunt doen is een simpele GET request op een endpoint die geen authenticatie behoeft. Dit zou een gebruiker of read-only informatie op een open source project kunnen zijn. Bijvoorbeeld, als we meer willen weten van een gebruiker genaamd “schacon”, kunnen we zoiets uitvoeren:

$ 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"
}

Er zijn honderden van soortgelijke endpoint als deze om informatie over organisaties, projecten, issues, commits te verkrijgen — zo ongeveer alles wat je publiekelijk kan zien op GitHub. Je kunt de API zelfs gebruiken om willekeurige MarkDown te tonen of een .gitignore template vinden.

$ 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 http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}

Reageren op een issue

Echter, als je een actie wilt uitvoeren op de website zoals reageren op een Issue of Pull Request of als je gesloten informatie wilt zien of ermee interacteren, zal je je moeten authenticeren.

Er zijn verschillende manieren om je te authenticeren. Je kunt eenvoudige authenticatie gebruiken met gewoon je gebruikersnaam en wachtwoord, maar over het algemeen is het een beter idee om een persoonlijke toegangs bewijs (access token) te gebruiken. Deze kan je genereren vanaf de “Applications” tab van je instellingen pagina.

Access Token
Figure 134. Genereer je access token vanaf de “Applications” tab op je instellingen pagina.

Het zal je vragen welke contexten je wilt voor deze token en een omschrijving. Zorg ervoor dat je een goede omschrijving gebruikt zo dat je met vertrouwen het token kan weggooien als je script of applicatie niet langer meer in gebruik is.

GitHub laat je het token maar één keer zien, dus zorg ervoor dat je het kopieert. Je kunt deze nu gebruiken om te authenticeren in je script in plaats van een gebruikersnaam en wachtwoord. Dit is handig omdat je de context waarin je iets wilt doen kan beperken en het token is weer intrekbaar.

Het heeft ook het bijkomende voordeel dat het je aanvraag limiet verhoogt. Zonder authenticatie ben je gelimiteerd tot 60 aanvragen per uur. Als je authenticeert kan je tot 5.000 aanvragen per uur doen.

Dus laten we het gebruiken om een reactie te geven op een van onze issues. Stel dat we een reactie willen geven op een specifieke issue, Issue #6. Om dit te doen moeten we een HTTP POST request op repos/<user>/<repo>/issues/<num>/comments uitvoeren met het token wat we zojuist gegeneerd hebben als een Authorization header.

$ 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:"
}

Als je nu naar dat issue gaat, kan je de reactie zien dat we zojuist succesvol gepost hebben in Een commentaar gepost via de GitHub API..

Reactie via API
Figure 135. Een commentaar gepost via de GitHub API.

Je kun de API gebruiken om zo ongeveer alles te doen wat je op website kunt doen — mijlpalen maken en zetten, mensen aan issues en pull requests toewijzen, labels maken en wijzigen, commit gegevens benaderen, nieuwe commits en branches maken, Pull Requests openen, sluiten of mergen, teams maken en wijzigen, reageren op regels code in een Pull Request, op de site zoeken enzovoorts, etcetera.

De status van een Pull Request wijzigen

We zullen nog een laatste voorbeeld bekijken omdat het echt handig is als je werkt met Pull Requests. Elke commit kan een of meerdere statussen hebben en er is een API om een status toe te voegen en deze uit te vragen.

De meeste Continuous Integration en test services gebruiken deze API om op pushes te reageren door de code die is gepushed te testen, en dan terug te melden of die commit alle tests heeft gepasseerd. Je kunt dit ook gebruiken om te kijken of het commit bericht juist is geformatteerd, of de indiener al je bijdrage richtlijnen heeft gevolgd, of de commit juist getekend was — verzin het maar.

Laten we stellen dat je een webhook op je repository ingericht hebt die een kleine webservice aanroept die controleert of er een Signed-off-by letterreeks in het commit bericht voorkomt.

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

Hopelijk is dit redelijk eenvoudig te volgen. In deze webhook verwerker kijken we door elke commit die zojuist is gepushed, we zoeken naar de reeks Signed-off-by in het commit bericht en tenslotten POSTen we via HTTP naar de /repos/<user>/<repo>/statuses/<commit_sha> API endpoint met de status.

In dit geval kan je een status (success, failure, error) sturen, een omschrijving wat er gebeurd is, een doel URL waar de gebruiker heen kan gaan voor meer informatie en een “context” in geval er meerdere statussen voor een enkele commit zijn. Bijvoorbeeld, een test-service kan een status aangeven en een validatie service zoals deze kan ook een status aangeven — het “context” veld maakt hierin het onderscheid.

Als iemand een nieuwe Pull Request op GitHub opent en deze hook is opgezet, kan je misschien iets zoals Commit status via de API. zien.

Commit status
Figure 136. Commit status via de API.

Je kunt nu een klein groen vinkje zien naast de commit die “Signed-off-by” in het bericht heeft staan en een rode kruis door die waar de auteur is vergeten te tekenen. Je kunt ook zien dat de Pull Request de status krijgt van de laatste commit op de branch en waarschuwt je als het niet geslaagd is. Dit is erg handig als je deze API gebruikt voor test resultaten, zodat je niet perongeluk iets merged waar de laatste commit tests laat falen.

Octokit

Alhoewel we ongeveer alles middels curl en eenvoudige HTTP requests hebben gedaan in deze voorbeelden, bestaan er diverse open source libraries die deze API in een meer taalspecifieke manier beschikbaar maken. Op het moment van schrijven, zijn de ondersteunde talen onder andere Go, Objective-C, Ruby en .NET. Kijk op http://github.com/octokit voor meer informatie hiervoor, omdat ze veel van de HTTP voor je afhandelen.

Hopelijk kunnen deze instrumenten je helpen om GitHub aan te passen en te wijzigen zodat deze beter werkt voor jouw specifieke workflows. Voor volledige documentatie over de hele API zowel als handleidingen voor veelvoorkomende taken, verwijzen we je naar https://developer.github.com.