Added Work_Log_Generator

This commit is contained in:
73VW 2018-10-04 19:31:58 +02:00
parent f2a4a5be6b
commit 49c0a13f8c
6 changed files with 408 additions and 0 deletions

View File

@ -0,0 +1,46 @@
`Work log generator`
--------------------
📝 C'est quoi?
===============
Ce simple script python permet de générer un journal de travail au format rst à partir des commits de l'un de vos dépôts.
🔘 Comment l'utiliser?
=======================
Il est nécessaire de commencer par générer un jeton d'accès et de l'entrer dans le premier champ de la fenêtre.
Pour le générer, rendez-vous `ici`_ dans la section "Personal access tokens".
À présent, il est possible de presser sur le bouton de connexion. Dès lors, une liste déroulante affiche les dépôts disponibles.
Après le choix du dépôt, le dernier bouton permet d'ouvrir le log, de le modifier et de le sauvegarder au format rst.
Il est maintenant possible de le convertir en utilisant pandoc ou n'importe quelle autre convertisseur que vous préférez.
Enjoy!
📝 What is this?
================
This simple python script allows you to generate a worklog in rst format based on your repo commits.
🔘 How to use it?
=================
Simply generate a personnal access token and enter it in the first field of the window.
In order to generate this token, go `here`_ under "Personal access tokens".
Then, it is possible to press on the connection button. Since then a dropdown list display the available repositories.
After choosing the repository, the last button allows you to open the log, edit it and save it in rst format.
You can then convert it using pandoc or any other converter you prefer.
Enjoy!
.. _`ici`: https://github.com/settings/tokens
.. _`here`: https://github.com/settings/tokens

View File

@ -0,0 +1,4 @@
# WorkLog
pygithub
PyQt5
qdarkstyle

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,358 @@
"""Get commits for the repo specified as parameter and write work log."""
import os
import sys
from pathlib import Path
import qdarkstyle
from github import Github
from github.GithubException import BadCredentialsException
from PyQt5 import Qt
from PyQt5 import QtCore
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QIcon
from PyQt5.QtGui import QMovie
from PyQt5.QtWidgets import QAction
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QComboBox
from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtWidgets import QPlainTextEdit
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QWidget
sys.settrace
APP_NAME = 'Work Log Generator'
RESOURCES_FOLDER = 'resources/'
ICON_PATH = RESOURCES_FOLDER + 'icone.ico'
LOADER_PATH = RESOURCES_FOLDER + 'loader.gif'
SAVE_ICON_PATH = RESOURCES_FOLDER + 'save.png'
class WorkLogPreviewer(QMainWindow):
"""
Worklog previewer class.
Extends QMainWindow
"""
sig = pyqtSignal(str, name='update')
def __init__(self, parent=None, repository=None, systemtray_icon=None):
"""Init window."""
super(WorkLogPreviewer, self).__init__(parent)
saveAct = QAction(QIcon(SAVE_ICON_PATH), '&Save', self)
saveAct.setShortcut('Ctrl+S')
saveAct.setStatusTip('Save work log')
saveAct.triggered.connect(self.save)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(saveAct)
self.repository = repository
self.systemtray_icon = systemtray_icon
self.statusBar()
widget = QWidget()
layout = QVBoxLayout()
self.te = QPlainTextEdit()
layout.addWidget(self.te)
self.lbl = QLabel()
self.lbl.hide()
self.movie = QMovie(LOADER_PATH)
self.lbl.setMovie(self.movie)
hlayout = QHBoxLayout()
hlayout.addStretch()
hlayout.addWidget(self.lbl)
hlayout.addStretch()
layout.addLayout(hlayout)
self.generate_log()
widget.setLayout(layout)
widget.setFixedSize(500, 500)
self.setCentralWidget(widget)
self.setWindowTitle(f'Work log for {repository.full_name}')
self.setWindowIcon(QIcon(ICON_PATH))
self.setLocale(QtCore.QLocale())
self.adjustSize()
self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
def generate_log(self):
"""Launch thread used to generate log."""
self.lbl.show()
self.movie.start()
self.sig.connect(self.display_log)
self.workThread = WorkLogThread(self, self.repository, self.sig)
self.workThread.start()
def display_log(self, log):
"""Display log received from thread."""
self.lbl.hide()
self.movie.stop()
self.te.setPlainText(log)
btMessage = "Log generation successfull!"
self.systemtray_icon.showMessage(
APP_NAME, btMessage, QIcon(ICON_PATH), 5000)
self.statusBar().showMessage(btMessage)
def save(self):
"""Save log to file."""
home = str(Path.home())
self.output = ""
self.output = QFileDialog.getSaveFileName(self,
'Save file',
home,
"ReST files (*.rst)")
if self.output[0] is not "":
with open(self.output[0], 'w') as f:
f.write(self.te.toPlainText())
btMessage = f'File saved as {self.output[0]}.'
else:
btMessage = "Can't save. No file specified."
self.systemtray_icon.showMessage(
APP_NAME, btMessage, QIcon(ICON_PATH), 5000)
self.statusBar().showMessage(btMessage)
class MainWidget(QWidget):
"""
Worklog Generator class.
Extends QWidget
"""
sig = pyqtSignal(list, name='update')
def __init__(self, parent=None):
"""Init widget."""
super(MainWidget, self).__init__(parent)
layout = QVBoxLayout()
self.parent = parent
self.ght = QLineEdit()
self.ght.setPlaceholderText("Github Token")
self.ght_keyPressEvent = self.ght.keyPressEvent
self.ght_original_style = self.ght.styleSheet()
self.ght.keyPressEvent = self.line_keyPressEvent
layout.addWidget(self.ght)
self.btn = QPushButton("Connect to github")
self.btn.clicked.connect(self.getRepos)
layout.addWidget(self.btn)
self.combo = QComboBox()
self.combo.setDisabled(True)
layout.addWidget(self.combo)
self.btn_save = QPushButton("Open worklog")
self.btn_save.setDisabled(True)
self.btn_save.clicked.connect(self.open_log)
layout.addWidget(self.btn_save)
self.lbl = QLabel()
self.lbl.hide()
self.movie = QMovie(LOADER_PATH)
self.lbl.setMovie(self.movie)
hlayout = QHBoxLayout()
hlayout.addStretch()
hlayout.addWidget(self.lbl)
hlayout.addStretch()
layout.addLayout(hlayout)
self.setLayout(layout)
self.setLocale(QtCore.QLocale())
self.sig.connect(self.add_repo_to_combobox)
def line_keyPressEvent(self, event):
"""Detect enter or return key pressed."""
if (event.key() == QtCore.Qt.Key_Enter
or event.key() == QtCore.Qt.Key_Return):
self.getRepos()
else:
self.ght_keyPressEvent(event)
def open_log(self):
"""Build rst file from repository commits and opens it."""
if self.parent is not None:
self.parent.statusBar().showMessage('Opening preview.')
repo = self.combo.itemData(self.combo.currentIndex())
self.preview = WorkLogPreviewer(None,
repo, self.parent.systemtray_icon)
self.preview.show()
if self.parent is not None:
self.parent.statusBar().showMessage('Done.')
def getRepos(self):
"""Get repos for user and add them in a combobox."""
if self.ght.text() is not "":
if self.parent is not None:
self.parent.statusBar().showMessage('Fetching repos...')
self.lbl.show()
self.movie.start()
self.ght.setStyleSheet(self.ght_original_style)
token = self.ght.text()
self.g = Github(token)
try:
if self.workThread is not None and self.workThread.isRunning():
return
except AttributeError:
pass
finally:
self.workThread = ConnectionThread(self, self.g, self.sig)
self.workThread.start()
else:
self.ght.setStyleSheet("QLineEdit { border: 2px solid red; }")
def add_repo_to_combobox(self, repo_list):
"""Add repos from repo_list to combobox."""
if len(repo_list) is not 0:
for repo in repo_list:
self.combo.addItem(repo.full_name, repo)
self.combo.setDisabled(False)
self.btn_save.setDisabled(False)
self.lbl.hide()
self.movie.stop()
class WorkLogThread(QtCore.QThread):
"""Thread used to write work log from repository."""
def __init__(self, parent, repository=None, sig=None):
"""Init thread."""
super(WorkLogThread, self).__init__(parent)
self.sig = sig
self.repository = repository
self.parent = parent
def run(self):
"""Run thread."""
message = "Journal de travail"
restTructuredText = message + os.linesep
restTructuredText += '=' * len(message) + os.linesep * 2
for commit in self.repository.get_commits():
com = commit.commit
date = com.author.date
restTructuredText += str(date) + os.linesep
restTructuredText += '-' * len(str(date)) + os.linesep * 2
restTructuredText += self.format_message_for_rst(com.message)
self.sig.emit(restTructuredText)
def format_message_for_rst(self, message):
"""Format message for a nice rst print."""
new_message = ""
split_message = message.splitlines()
for i in range(len(split_message)):
if i is not 0 and split_message[i] is not "":
new_message += "- "
new_message += split_message[i] + "\n" * 2
return new_message
class ConnectionThread(QtCore.QThread):
"""Thread used to connect to github."""
def __init__(self, parent, g=None, sig=None):
"""Init thread."""
super(ConnectionThread, self).__init__(parent)
self.g = g
self.sig = sig
self.parent = parent
def run(self):
"""Run thread."""
repo_list = []
try:
for repo in self.g.get_user().get_repos():
repo_list.append(repo)
if self.parent is not None:
self.parent.parent.statusBar().showMessage('Done.')
sys_tray = self.parent.parent.systemtray_icon
sys_tray.showMessage(
APP_NAME, 'Connected to github', QIcon(ICON_PATH), 5000)
except BadCredentialsException as e:
if self.parent is not None:
self.parent.parent.statusBar().showMessage(str(e))
self.sig.emit(repo_list)
class Window(QMainWindow):
"""Personal mainWindow class."""
def __init__(self, systemtray_icon=None, parent=None):
"""Init window."""
super(Window, self).__init__(parent)
self.systemtray_icon = systemtray_icon
self.statusBar()
self.widget = MainWidget(self)
self.setCentralWidget(self.widget)
self.resize(500, 200)
self.setWindowTitle(APP_NAME)
self.setWindowIcon(QIcon(ICON_PATH))
self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
helpAct = QAction('&Help', self)
helpAct.setShortcut('Ctrl+H')
helpAct.setStatusTip('Help')
helpAct.triggered.connect(self.helper)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&About')
fileMenu.addAction(helpAct)
def helper(self):
"""Display help."""
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("This simple python script allows you to generate a "
"worklog in rst format based on your repo commits.")
msg.setInformativeText("You need to generated a token first.")
msg.setWindowTitle("Help")
msg.setWindowIcon(QIcon(ICON_PATH))
msg.setDetailedText("Simply generate a personnal access token and "
"enter it in the first field of the window."
"\r\n"
"In order to generate this token, go to "
"https://github.com/settings/tokens "
"under \"Personal access tokens\".")
msg.exec_()
if __name__ == "__main__":
app = QApplication(list(sys.argv))
icon = QIcon(ICON_PATH)
systemtray_icon = Qt.QSystemTrayIcon(icon, app)
systemtray_icon.show()
window = Window(systemtray_icon)
window.show()
sys.exit(app.exec_())