GitHub i Django

W jednym z djangowych projektów chciałem wyświetlać na stronie informacje o ostatnim commicie z repozytorium Gita. GitHub daje do tego eleganckie REST-owe API, więc pozostało tylko podpiąć wywołanie API pod szablon Django.

Żeby nie babrać się samemu z wywołaniami łebserwisu, dekodowaniem wyników itp., poszukałem jakiejś Pythonowej biblioteki (zgodnie z wielokrotnie sprawdzającą się zasadą, że do wszystkiego jest jakiś moduł Pythona ;) ). Na GitHubie znalazłem nawet dwie propozycje, postanowiłem skorzystać z tej drugiej - python-github2. Link do PyPI wprawdzie nie działa, przez easy_install też nie mogłem zainstalować, ale przecież jest repozytorium. No to instalujemy:

git clone git://github.com/ask/python-github2.git
cd python-github2
python setup.py build
python setup.py install

Czyli nic strasznego, zwykła procedura instalacji. Przykłady użycia są w pliku README w repozytorium. Zasada jest taka: tworzymy jeden obiekt klasy Github, podając nazwę użytkownika i token, a właściwe wywołania API są wykonywane dopiero później, gdy odwołamy się do którejś z metod obiektów składowych. Przykładowo:

from github2.client import Github
github = Github(username="...", api_token=".......")
repo = github.repos.show("uzytkownik/repozytorium")

Nazwę użytkownika i token do API zdefiniowałem w głównym pliku settings.py projektu w zmiennych GITHUB_USER i GITHUB_API_TOKEN. Pozostała kwestia pożenienia tego wszystkiego z szablonem. Rozsądne rozwiązanie to utworzenie własnego znacznika szablonu. Tak też zrobiłem, wykorzystując inclusion_tag. Dlaczego akurat tak? Bo chciałem mieć możliwość konfigurowania, które dokładnie informacje o commicie chcę pokazywać. Definicja znacznika znajduje się w katalog_aplikacji\templatetags\github.py (należy pamiętać o dodaniu aplikacji do krotki INSTALLED_APPS w ustawieniach projektu).

from github2.client import Github
from django import template
from django.conf import settings

register = template.Library()

@register.inclusion_tag("tools/commit.html")
def last_commit(repository, branch):
    try:
        github = Github(settings.GITHUB_USER, settings.GITHUB_API_TOKEN)
        commits = github.commits.list(repository, branch)
        return {'commit': commits[0]}
    except:
        return {'commit': None}

Funkcja ma dwa argumenty, jeden określa nazwę repozytorium (włącznie z nazwą użytkownika, np. "zsiciarz/aquila"), a drugi gałąź w repo. Żeby cokolwiek było wyświetlone, należy utworzyć szablon tools/commit.html. Słownik zwracany przez funkcję znacznika stanowi kontekst szablonu. Zatem mamy dostęp do zmiennej o nazwie commit. Przykładowy szablon przedstawiam poniżej.

{% if commit %}
  <p class="github_message">{{ commit.message }}</p>
  <footer>
    <ul>
      <li>Committed by <strong>{{ commit.author.login }}</strong>
      <time>{{ commit.committed_date }}</time></li>
      <li><a href="{{ commit.url }}">See at GitHub</a></li>
    </ul>
  </footer>
{% else %}
  <p>Sorry, GitHub returned an error.</p>
{% endif %}

Możemy teraz w elegancki sposób pokazać informacje o commicie za pomocą naszego znacznika.

{% load github %}
{% last_commit "uzytkownik/repozytorium" "master" %}