Comment être notifié d'une nouvelle release d'un projet hébérgé sur Github
Publié le
Si vous exploitez de nombreux projets publiés sur GitHub, il devient difficile avec le temps de suivre leurs mises à jour. Voici une petite solution maison pour être notifié par mail lorsque l'un de ces projets publie une release.
Le principe est simple, un script est lancé à intervalles réguliers (via un job Cron par exemple) et va se charger de :
- consulter le fil Atom des versions publiées par le projet, ces urls sont du type :
https://github.com/user/repository/releases.atom
et contiennent les dernières releases avec pour chacune la date de publication, l'auteur et le contenu de la mise à jour (si renseigné par l'auteur), - vérifier la date de chaque release par rapport à la dernière consultation du fil,
- envoyer un mail contenant la liste des nouveautés si des entrées sont plus récentes.
Plusieurs choix techniques pour l'implémenter, mais je suis parti sur Python, je me demande encore pourquoi (le typage est horrible, la doc craint, …) car il assure une portabilité accrue (et surtout parce que j'ai pu pompé allégrement du code pour parser le fil Atom…)
Prérequis évident : installer Python et les quelques librairies nécessaires : apt-get install python python-feedparser python-dateutil
.
Voilà le script dans son intégralité (commentaire en anglais basique ; je les ai écrits, vous devriez pouvoir les comprendre ^^ ) :
#!/usr/bin/python
import feedparser
import logging
import sys
from datetime import datetime
from dateutil.parser import parse
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from subprocess import Popen, PIPE
# declare projects
github_release_rss_urls = [
'https://github.com/nioc/tumblr-photo-browse/releases.atom',
'https://github.com/nioc/web-music-player/releases.atom'
]
# declare mail parameters
mail_from = 'github-notifier'
mail_to = 'vous@domain.tld'
# declare log file
log_file = '/var/log/github-notifier.log'
# declare timestamp file
timestamp_filename = '/usr/local/bin/github-release-notifier/github_notifier_timestamp'
# Log level of the script. Values are :
# logging.DEBUG
# logging.INFO
# logging.WARNING
# logging.ERROR
# logging.CRITICAL
log_level = logging.INFO
#======================= DO NOT CHANGE BELOW =======================#
try:
logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%b %d %Y %H:%M:%S', level=log_level, filename=log_file)
logging.info('Start of github-notifier')
except IOError as e:
sys.exit(1)
# get last timestamp
timestamp = parse(datetime.utcnow().isoformat())
try:
logging.debug(' Read last timestamp')
previous_timestamp_file = open(timestamp_filename, 'r')
previous_timestamp = parse(previous_timestamp_file.read())
previous_timestamp_file.close()
except IOError as e:
logging.warning(' No file found for last timestamp on local system')
previous_timestamp = parse(datetime.utcnow().isoformat())
except ValueError as e:
logging.error(' Invalid last timestamp')
previous_timestamp = parse(datetime.utcnow().isoformat())
logging.debug(' Last timestamp='+previous_timestamp.isoformat())
# prepare message contents
message_content_html = ''
message_content_text = ''
some_project_has_new_release = False
# request each feeds
for url in github_release_rss_urls:
logging.debug(' Processing '+url)
# clear message content of the project
message_content_project_html = ''
message_content_project_text = ''
project_has_new_release = False
feed = feedparser.parse( url )
# handle new feeds
for entry in feed.entries:
logging.debug(' Processing entry')
entry_datetime = datetime.strptime(entry.updated, '%Y-%m-%dT%H:%M:%SZ')
if previous_timestamp < entry_datetime:
# this is a new entry
logging.debug(' Entry is new')
project_has_new_release = True
some_project_has_new_release = True
message_content_project_html = message_content_project_html + '<br />' + entry.author + ' released ' + entry.title + ' (' + entry.updated + ')'
message_content_project_text = message_content_project_text + '\r\n - ' + entry.author + ' released ' + entry.title + ' (' + entry.updated + ')'
if entry.content:
# there is a content description
message_content_project_html = message_content_project_html + '<br />' + entry.content[0].value
# test if there was new item
if project_has_new_release:
logging.info(' New release available for '+url)
message_content_html = message_content_html + '<br/><h3><a href="' + feed.feed.link + '">"' + feed.feed.title + '</a></h3>' + message_content_project_html
message_content_text = message_content_text + '\r\n\r\n' + feed.feed.title + message_content_project_text
# there is some new versions, send mail
if some_project_has_new_release:
logging.debug(' Prepare message')
# prepare message
message_content_html = 'There is a new releases for followed project on Github:' + message_content_html
message_content_text = 'There is a new releases for followed project on Github:' + message_content_text
# prepare mail
msg = MIMEMultipart('alternative')
msg['From'] = mail_from
msg['To'] = mail_to
msg['Subject'] = 'New releases on followed Github projects'
part1 = MIMEText(message_content_text, 'plain')
part2 = MIMEText(message_content_html, 'html')
msg.attach(part1)
msg.attach(part2)
# send mail
try:
p = Popen(['/usr/sbin/sendmail', '-t', '-oi'], stdin=PIPE)
p.communicate(msg.as_string())
except OSError as e:
logging.error(' Error sending mail')
# set current timestamp
logging.debug(' Store timestamp')
timestamp_file = open(timestamp_filename,'w')
timestamp_file.write(timestamp.isoformat())
timestamp_file.close()
logging.info('End of github-notifier')
C'est tout pour aujourd'hui. Si vous avez d'autres idées pour être notifié de la release d'un projet hébergé sur Github ou que vous voulez améliorer le script, laissez un commentaire :)