├── .gitignore ├── Makefile ├── Procfile ├── README.md ├── requirements.apt ├── requirements.txt ├── run.py ├── setup-virtualenv.sh ├── template.html ├── tsuru.yaml └── update-index.sh /.gitignore: -------------------------------------------------------------------------------- 1 | index.html 2 | config.yaml 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: deploy 2 | 3 | deploy: 4 | python run.py 5 | tsuru app-deploy -a top index.html 6 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | nginx: /usr/sbin/nginx -g "daemon off;" 2 | watcher: ./update-index.sh 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hackaton Rank 2 | Top projetos em número de commits do #hackinpoa 3 | 4 | O serviço tá disponível em: 5 | http://top.app.hackinpoa.tsuru.io 6 | -------------------------------------------------------------------------------- /requirements.apt: -------------------------------------------------------------------------------- 1 | libxml2-dev 2 | libxslt-dev 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | jinja2 2 | requests 3 | beautifulsoup4 4 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import requests 4 | from bs4 import BeautifulSoup 5 | from collections import namedtuple 6 | from requests.auth import HTTPBasicAuth 7 | from jinja2 import Template 8 | 9 | 10 | username = os.environ.get("GITHUB_USERNAME", "hackinpoawatcher") 11 | password = os.environ.get("GITHUB_PASSWORD", "PASSWORD") 12 | auth = HTTPBasicAuth(username, password) 13 | 14 | REPO_STATS_URL_FORMAT = "https://api.github.com/repos/{owner}/{repo}/stats/contributors" 15 | WATCHING_URL_FORMAT = "https://api.github.com/users/{user}/subscriptions" 16 | REPO_URL_FORMAT = "https://github.com/{owner}/{repo}" 17 | LANG_URL_FORMAT = "https://api.github.com/repos/{owner}/{repo}/languages" 18 | 19 | Language = namedtuple('Language', ['name', 'lines'], verbose=True) 20 | 21 | def get_repos_info(): 22 | repos = [get_repo_info(owner, repo) for owner, repo in get_repos()] 23 | return sorted(repos, key=lambda r: -r['total_commits']) 24 | 25 | 26 | def get_repos(): 27 | url = WATCHING_URL_FORMAT.format(user=username) 28 | data = requests.get(url, auth=auth, params={'per_page': '100'}).json() 29 | return [r['full_name'].split("/") for r in data] 30 | 31 | 32 | def get_repo_info(owner, repo): 33 | authors = get_authors_info(owner, repo) 34 | languages = get_lang_info(owner, repo) 35 | data = { 36 | 'owner': owner, 37 | 'languages': languages, 38 | 'repo': repo, 39 | 'authors': authors, 40 | 'url': 'https://github.com/{owner}/{repo}'.format(owner=owner, repo=repo), 41 | } 42 | data.update(get_page_data(owner, repo)) 43 | return data 44 | 45 | 46 | def get_page_data(owner, repo): 47 | url = REPO_URL_FORMAT.format(owner=owner, repo=repo) 48 | resp = requests.get(url) 49 | soup = BeautifulSoup(resp.content) 50 | return { 51 | 'total_commits': get_total_commits(soup), 52 | 'last_commit': get_last_commit(soup) 53 | } 54 | 55 | def get_total_commits(soup): 56 | result = soup.select(".commits .num") 57 | if not result: 58 | return 0 59 | return int(result[0].text.strip()) 60 | 61 | 62 | def get_last_commit(soup): 63 | result = soup.select(".commit-title") 64 | if not result: 65 | return "" 66 | text = result[0].text.strip() 67 | if text.startswith('Fetching latest commit'): 68 | return "" 69 | return text 70 | 71 | 72 | def get_lang_info(owner, repo): 73 | url = LANG_URL_FORMAT.format(owner=owner, repo=repo) 74 | print url 75 | languages_request = requests.get(url, auth=auth) 76 | if languages_request.status_code == 204: 77 | return [] 78 | data = languages_request.json() 79 | langs = [Language(name, lines) for name, lines in data.items()] 80 | return sorted(langs, key=lambda l: -l.lines) 81 | 82 | 83 | def get_authors_info(owner, repo): 84 | url = REPO_STATS_URL_FORMAT.format(owner=owner, repo=repo) 85 | print url 86 | for tries in range(5): 87 | authors_request = requests.get(url, auth=auth) 88 | if authors_request.status_code == 200: 89 | break 90 | print 'Request failed. Sleeping...' 91 | time.sleep(5) 92 | if authors_request.status_code == 204: 93 | return [] 94 | authors = authors_request.json() 95 | author_infos = [author_info(author) for author in authors if author['author']] 96 | return sorted(author_infos, key= lambda a: -a['commits']) 97 | 98 | 99 | def author_info(author): 100 | name = author['author']['login'] 101 | avatar = author['author']['avatar_url'] 102 | commits = sum([w['c'] for w in author['weeks']]) 103 | return {"avatar": avatar, "name": name, "commits": commits} 104 | 105 | 106 | def render(repos): 107 | template_content = open('template.html').read().decode('utf-8') 108 | template = Template(template_content) 109 | return template.render(repos=repos) 110 | 111 | 112 | if __name__ == '__main__': 113 | repos = get_repos_info() 114 | with open("index.html", "w") as f: 115 | f.write(render(repos).encode('utf-8')) 116 | -------------------------------------------------------------------------------- /setup-virtualenv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VIRTUALENV_PATH=/home/application/.top 4 | 5 | if [ ! -d $VIRTUALENV_PATH ] 6 | then 7 | virtualenv $VIRTUALENV_PATH 8 | fi 9 | 10 | $VIRTUALENV_PATH/bin/pip install -r /home/application/current/requirements.txt 11 | -------------------------------------------------------------------------------- /template.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 |# | 55 |Repositório | 56 |57 | | Commits | 58 |
---|---|---|---|
{{ loop.index }} | 64 |65 | 66 | {{ repo.owner }}/{{ repo.repo }} 67 | 68 | 69 | {% for lang in repo.languages %} 70 | {{ lang.name|lower }} 71 | {% endfor %} 72 | 73 | 74 | {{ repo.last_commit }} 75 | 76 | | 77 |
78 | {% for author in repo.authors %}
79 |
80 | |
84 | {{ repo.total_commits }} | 85 |
92 | Código disponível "de grátis" no GitHub! 93 |
94 |