Agréger les journaux Git à l'aide de Git Python et analyser les associations à l'aide d'Orange

Je suis honoré d'être en charge de la veille de Noël au Lux Advent Calendar 2016. Je poste de manière responsable sur Eve (en regardant la station M).


introduction

La commande git log est un outil pratique indispensable pour la gestion des versions qui vous permet de savoir quand, qui a commis quoi et comment. Cependant, si vous souhaitez utiliser cela pour le contrôle et l'analyse de la qualité, vous devez en concevoir un peu. Dans Introduction, j'ai essayé de résumer comment formater git log avec une seule ligne, mais il y a une limite à ce qui peut être fait en une seule ligne. Dans le travail réel, il y a d'autres choses à faire après la mise en forme des journaux, comme la collecte des journaux tous les matins pour vérifier l'état du développement, la planification des tests et l'évaluation de la qualité à la fin du projet, donc cette fois J'ai réfléchi à la façon d'utiliser le journal pratiquement.

Agrégation à l'aide de Python

Donc, cette fois, j'ai résumé comment agréger et analyser les journaux Git à l'aide de Git Python. Je pense qu'il existe des moyens de gérer Git dans d'autres langues, mais je suis bon en tabulation et en analyse car c'est un langage qui vous permet de réécrire facilement le code afin que vous puissiez facilement vérifier la qualité en fonction de la situation du projet. Je pensais que Python était facile à gérer en tant que langage de script. Au fait, Python n'a écrit que du code de niveau jetable tel qu'une petite agrégation comme cette fois, alors pardonnez-moi s'il peut y avoir une partie médiocre du code. Veuillez commenter si vous en avez.

L'exemple de code résumé ici est confirmé avec Python 2.7.

GitPython

Il existe une bibliothèque pratique appelée GitPython pour travailler avec Git en Python. Veuillez vous référer aux Documents officiels pour les procédures d'installation.

Obtenir des informations de validation

Obtenez en spécifiant le référentiel local avec Repo ('/ path'). Et vous pouvez obtenir les informations de validation pour une branche particulière avec Repo.iter_commits ..

from git import *
import datetime, time

repo = Repo('./')
for item in repo.iter_commits('master', max_count=10):
    dt = datetime.datetime.fromtimestamp(item.authored_date).strftime("%Y-%m-%d %H:%M:%S")
    print("%s %s %s " % (item.hexsha, item.author, dt))

Pour les informations de commit qui peuvent être obtenues, reportez-vous à Objects.Commit API Reference.

L'exemple ci-dessus renvoie la valeur de hachage, l'utilisateur engagé et la date et l'heure de validation des 10 derniers journaux Git de la branche maître sur le référentiel dans le répertoire actuel.

Exemple de sortie


ddffe26850e8175eb605f975be597afc3fca8a03 Sebastian Thiel 2016-12-22 20:51:02 
3d6e1731b6324eba5abc029b26586f966db9fa4f Sebastian Thiel 2016-12-22 20:48:59 
82ae723c8c283970f75c0f4ce097ad4c9734b233 Sebastian Thiel 2016-12-22 20:44:14 
15b6bbac7bce15f6f7d72618f51877455f3e0ee5 Sebastian Thiel 2016-12-22 20:35:30 
c823d482d03caa8238b48714af4dec6d9e476520 Sebastian Thiel 2016-12-09 00:34:04 
b0c187229cea1eb3f395e7e71f636b97982205ed Sebastian Thiel 2016-12-09 00:07:11 
f21630bcf83c363916d858dd7b6cb1edc75e2d3b Sebastian Thiel 2016-12-09 00:01:35 
06914415434cf002f712a81712024fd90cea2862 Sebastian Thiel 2016-12-08 22:32:58 
2f207e0e15ad243dd24eafce8b60ed2c77d6e725 Sebastian Thiel 2016-12-08 21:20:52 
a8437c014b0a9872168b01790f5423e8e9255840 Vincent Driessen 2016-12-08 21:14:27 

À propos, l'exemple de sortie ci-dessus est le journal de validation de GitPython au 23 décembre 2016.

Spécification de la limitation de validation

La limitation de validation de git log introduite dans l'introduction peut être spécifiée par l'argument de ʻiter_commits (dans l'exemple ci-dessus, max_count = 10est spécifié). Vous pouvez en spécifier plusieurs avec,. Remplacez également la partie - par _pour spécifier. Au fait, la spécification deno_mergea entraîné une erreur de syntaxe. Comme décrit dans [here](https://git-scm.com/docs/git-rev-list#git-rev-list --- no-merges), en tant que spécification facultative degit logComme c'est la même chose quemax-parents = 1, j'ai pu utiliser max_parents = 1`.

Spécifier la plage de révision

Vous pouvez également spécifier la syntaxe à double point introduite dans l'introduction. Cela fait simplement ressembler la partie master ci-dessus à master..experiment.

Application pour l'agrégation et l'analyse de journaux

Considérons maintenant l'application pour enregistrer l'agrégation et l'analyse. Toutes les informations du fichier validé sont accrochées dans les informations de validation obtenues par le code ci-dessus. Vous pouvez obtenir une liste d'informations sur les fichiers validés avec stats.files.

Détails des informations pour chaque fichier de validation

Ceci est un exemple de sortie standard au format CSV avec des informations telles que la date et l'heure auxquelles la ligne ajoutée et la ligne supprimée pour chaque fichier validé ont été validées.

from git import *
import datetime, time

repo = Repo('./')
print('hexsha,author,authored_date,file_name,deletions,lines,insertions')
for item in repo.iter_commits('master', max_count=10):
    file_list = item.stats.files
    for file_name in file_list:
        dt = datetime.datetime.fromtimestamp(item.authored_date).strftime("%Y-%m-%d %H:%M:%S")
        insertions = file_list.get(file_name).get('insertions')
        deletions = file_list.get(file_name).get('deletions')
        lines = file_list.get(file_name).get('lines')
        print("%s,%s,%s,%s,%s,%s,%s" % (item.hexsha, item.author, dt, file_name, insertions, deletions, lines))

Il est assez difficile d'obtenir ces informations avec une simple commande et de les mettre sur une seule ligne, mais avec GitPython, il vous suffit de faire le tour de la boucle et de l'obtenir.

Nombre de validations par fichier

Comptons maintenant le nombre de changements effectués pendant la période par fichier plutôt que par commit. Les données suivantes indiquent le nombre de fois engagées dans les 6 mois pour chaque fichier.

from git import *
import datetime, time

repo = Repo('./')
print('file_name,commit_count')
file_list = {}
for item in repo.iter_commits('master', since='6 months ago'):
    for fileName in item.stats.files:
        if file_name not in file_list:
            fileList[fileName] = []
        author = {}
        author[item.author] = datetime.datetime.fromtimestamp(item.authored_date).strftime("%Y-%m-%d %H:%M:%S")
        file_list[file_name].append(author)

for file_name in file_list:
    print("%s,%d" % (file_name, len(fileList[file_name])))

De plus, en appliquant cela, il semble possible d'agréger le nombre de lignes modifiées pour chaque fichier au cours de la période du projet, et de calculer l'intervalle de validation (le nombre de jours depuis le dernier changement). Vous pouvez agréger non seulement par fichier, mais également par jour, mois et personne engagée.

Utilisation du journal Git

Si Python peut être utilisé librement pour l'agrégation, les journaux peuvent être utilisés pour de nouveaux moyens tels que l'importation dans d'autres bibliothèques Python pour l'analyse et la liaison avec des outils et services externes.

Analyse d'association

Alors, pensons à associer l'analyse des informations de commit. Ce que je veux faire, c'est comment obtenir les informations selon lesquelles "la personne qui a modifié ce fichier a également changé cela". En Python, l'analyse d'association peut être effectuée avec une bibliothèque appelée Orange.

Comment utiliser Orange

Selon le document officiel Règles d'association et ensembles d'éléments fréquents, la liste à analyser est .basket au format CSV. Si vous l'enregistrez avec l'extension , Orange semble analyser l'association. Par conséquent, nous afficherons les fichiers qui ont été validés ensemble dans une seule validation au format CSV.

Analyse d'association des dossiers engagés l'année dernière

Tout d'abord, en appliquant la méthode ci-dessus, GitPython est utilisé pour sortir les fichiers qui ont été validés en même temps, séparés par des virgules.

commit-file-list.py


from git import *

repo = Repo('./')
for item in repo.iter_commits('master', since='1 years ago'):
    print(",".join(item.stats.files.keys()))
$ python commit-file-list.py > commit-file-list.basket

Analysons l'association de commit-file-list.basket créée ci-dessus en se référant à l'exemple de code d'Orange.

import Orange
data = Orange.data.Table('commit-file-list.basket')
rules = Orange.associate.AssociationRulesSparseInducer(data, support=0.02, confidence=0.5)
print "%4s %4s %4s" % ("Supp", "Conf", "Rule")
for r in rules:
    if 'git/config.py' in r.name:
        print "%4.1f %4.1f  %s" % (r.support, r.confidence, r)

Exemple de sortie


Supp Conf Rule
 0.0  0.6  git/test/test_git.py -> git/cmd.py
 0.0  0.2  git/cmd.py -> git/test/test_git.py
 0.1  0.7  git/test/test_diff.py -> git/diff.py
 0.1  0.7  git/diff.py -> git/test/test_diff.py
 0.0  0.4  git/test/test_diff.py -> git/diff.py doc/source/changes.rst

«support» n'est pas très important dans ce cas car c'est le pourcentage de la règle qui apparaît dans l'ensemble. Par conséquent, réglez la valeur de seuil aussi bas que possible. «confiance» est le rapport de la règle entière apparaissant sur la condition préalable d'une partie de la règle (le rapport de A et B basé sur tous les modèles, y compris A), donc cette valeur est exactement dans ce cas. Je veux souligner les règles élevées.

Recherchez "Je modifie également ce fichier" dans les règles d'analyse des associations avant de fusionner dans le fichier maître

Tout d'abord, sortez le fichier à fusionner au format CSV avec une ligne pour chaque commit, et créez un fichier .basket. Puisqu'il s'agit d'une cible à fusionner dans master, il obtient un commit en utilisant la syntaxe à double point et génère le fichier qui lui est associé.

merge-target-list.py


from git import *

repo = Repo('./')
for item in repo.iter_commits('master..experiment', max_parents=1):
    print(",".join(item.stats.files.keys()))
$ python merge-target-list.py > merge-target-list.basket

Il peut être préférable d'appliquer la méthode d'extraction des règles basée sur le journal Git pendant un an mentionnée ci-dessus, de trouver celle dont merge-target-list.basket à fusionner correspond à la gauche de la règle, et de valider également à droite. Affiche le résultat que cela ne peut pas être fait (par exemple, on suppose que A, B, C sont extraits en tant que règles du journal pendant un an, et C est sorti en tant que candidat si A, B existe dans la cible de fusion).

import Orange
data = Orange.data.Table('commit-file-list.basket')
rules = Orange.associate.AssociationRulesSparseInducer(data, support=0.02, confidence=0.5)
for r in rules:
    if 'git/config.py' in r.name:
        print "%4.1f %4.1f  %s" % (r.support, r.confidence, r)

merge_data = Orange.data.Table('merge-target-list.basket')
for d in merge_data:
    for rule in rules:
        #print rule
        if rule.applies_left(d):
            print (u"%Qui a commis s%3.1f %%À cette vitesse%s est aussi engagé" %(rule.left.get_metas(str).keys(), (rule.confidence*100), rule.right.get_metas(str).keys()))

Exemple de sortie


['git/test/test_remote.py']Qui a commis 55.0 %À cette vitesse['git/test/lib/helper.py']S'engage également
['git/test/test_remote.py']Qui a commis 55.0 %À cette vitesse['git/test/test_base.py']S'engage également
['git/test/test_remote.py']50 personnes qui se sont engagées.0 %À cette vitesse['git/util.py']S'engage également
['git/test/test_base.py']Qui a commis 55.0 %À cette vitesse['git/test/test_git.py']S'engage également
...(réduction)

Les candidats ont produit plus que ce à quoi je m'attendais pour fixer la confiance à 0,5. Je pense qu'il est préférable d'ajuster cette zone en fonction de la situation et des caractéristiques du projet.

en conclusion

Puisque Python a de nombreuses bibliothèques utiles, il semble qu'il puisse être appliqué non seulement à l'analyse d'association mais aussi à diverses applications. En fait, je pensais à utiliser matplotlib qui peut gérer des graphiques et faire du ChatBot, mais cette fois c'est parce que l'analyse d'association est devenue plus longue que prévu. J'aimerais continuer mes devoirs de vacances d'hiver.

référence

Exécutez Apriori depuis Python avec Orange Formater le journal Git avec une seule ligne


Le plaisir Lux Advent Calendar 2016 est enfin le dernier jour de demain. Veuillez attendre la clôture de @ kawanamiyuu avec impatience. Passez un bon Noël à tous.

Recommended Posts

Agréger les journaux Git à l'aide de Git Python et analyser les associations à l'aide d'Orange
Regroupez et analysez les prix des produits à l'aide de l'API Rakuten Product Search [Python]
Flux de développement Python avec Poetry, Git et Docker
Authentification à l'aide de l'authentification des utilisateurs tweepy et de l'authentification d'application (Python)
Clustering et visualisation à l'aide de Python et CytoScape
Analyser le journal de validation Git en Python
Notes utilisant cChardet et python3-chardet dans Python 3.3.1.
De Python à l'utilisation de MeCab (et CaboCha)
Utilisation de Python et MeCab avec Azure Databricks
Je veux analyser les journaux avec Python
J'utilise tox et Python 3.3 avec Travis-CI
Agréger les résultats des tests à l'aide de la bibliothèque Python QualityForward
Estimation de l'orientation de la tête avec Python et OpenCV + dlib
J'ai essayé le web scraping en utilisant python et sélénium
Remarques sur l'installation de Python3 et l'utilisation de pip sous Windows7
Développer et déployer des API Python à l'aide de Kubernetes et Docker
J'ai essayé la détection d'objets en utilisant Python et OpenCV
Obtenez le nom de la branche git et le nom de la balise avec python
Analysez les journaux d'accès Apache avec Pandas et Matplotlib
Créer une carte Web en utilisant Python et GDAL
[Python3] Génération automatique de texte avec janome et markovify
Essayez d'utiliser tensorflow ① Créez un environnement python et introduisez tensorflow
Essayez d'utiliser l'API ChatWork et l'API Qiita en Python