Intial commit
This commit is contained in:
		
							
								
								
									
										61
									
								
								jira_tracker/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								jira_tracker/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
import argparse, traceback, sys
 | 
			
		||||
from jira_tracker.logger import logger, enable_debug_logger
 | 
			
		||||
from jira_tracker.jira_auth import JiraAuth
 | 
			
		||||
from jira_tracker.project_tracker import ProjectTracker
 | 
			
		||||
 | 
			
		||||
version = "0.0.0"
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    
 | 
			
		||||
    parser = argparse.ArgumentParser(description="test")
 | 
			
		||||
    parser.add_argument("-d", "--debug", help="Enables debug logging and traceback", action="store_true", dest="debug", default=False)
 | 
			
		||||
    parser.add_argument("-v", "--version", help="Return current version number", dest="return_version", action="store_true", default=False)
 | 
			
		||||
    parser.add_argument("--update-config", help ="Prompts input for updating config file", dest="update_config", action="store_true", default=False)
 | 
			
		||||
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        if args.debug:
 | 
			
		||||
            enable_debug_logger()
 | 
			
		||||
 | 
			
		||||
        if args.return_version:
 | 
			
		||||
            print(version)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        auth = JiraAuth()
 | 
			
		||||
 | 
			
		||||
        if args.update_config:
 | 
			
		||||
            auth.stdin_configure()
 | 
			
		||||
            auth.update_config(auth.config_location)
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        row_format ="{:<12}{:<64}{:>4}{:>16}"
 | 
			
		||||
        print(row_format.format("Task","Summary","Points","Status"))
 | 
			
		||||
 | 
			
		||||
        points = 0
 | 
			
		||||
        jira_client = auth.get_client()
 | 
			
		||||
        all_issues = []
 | 
			
		||||
        for jira_project in jira_client.projects():
 | 
			
		||||
            logger.debug(f"Searching Project: {jira_project.key}")
 | 
			
		||||
            proj = ProjectTracker(jira_client, jira_project.key)
 | 
			
		||||
            issues = sorted(proj.this_weeks_issues(), key=lambda issue: issue.status)
 | 
			
		||||
            all_issues = all_issues + issues
 | 
			
		||||
            for issue in issues:
 | 
			
		||||
                if issue.status == "Done":
 | 
			
		||||
                    points = points + float(issue.points)
 | 
			
		||||
 | 
			
		||||
        for issue in all_issues:
 | 
			
		||||
            print(row_format.format(issue.name, issue.summary, issue.points, issue.status))
 | 
			
		||||
        print(f"\nTotal points this week: {points}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    except (Exception) as e:
 | 
			
		||||
        logger.critical(e)
 | 
			
		||||
        if args.debug:
 | 
			
		||||
            tb = sys.exc_info()[2]
 | 
			
		||||
            traceback.print_tb(tb)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										61
									
								
								jira_tracker/__init__.pye
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								jira_tracker/__init__.pye
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
import argparse, traceback, sys
 | 
			
		||||
from jira_tracker.logger import logger, enable_debug_logger
 | 
			
		||||
from jira_tracker.jira_auth import JiraAuth
 | 
			
		||||
from jira_tracker.project_tracker import ProjectTracker
 | 
			
		||||
 | 
			
		||||
version = "0.0.0"
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    
 | 
			
		||||
    parser = argparse.ArgumentParser(description="test")
 | 
			
		||||
    parser.add_argument("-d", "--debug", help="Enables debug logging and traceback", action="store_true", dest="debug", default=False)
 | 
			
		||||
    parser.add_argument("-v", "--version", help="Return current version number", dest="return_version", action="store_true", default=False)
 | 
			
		||||
    parser.add_argument("--update-config", help ="Prompts input for updating config file", dest="update_config", action="store_true", default=False)
 | 
			
		||||
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        if args.debug:
 | 
			
		||||
            enable_debug_logger()
 | 
			
		||||
 | 
			
		||||
        if args.return_version:
 | 
			
		||||
            print(version)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        auth = JiraAuth()
 | 
			
		||||
 | 
			
		||||
        if args.update_config:
 | 
			
		||||
            auth.stdin_configure()
 | 
			
		||||
            auth.update_config(auth.config_location)
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        row_format ="{:<12}{:<64}{:>4}{:>16}"
 | 
			
		||||
        print(row_format.format("Task","Summary","Points","Status"))
 | 
			
		||||
 | 
			
		||||
        points = 0
 | 
			
		||||
        jira_client = auth.get_client()
 | 
			
		||||
        all_issues = []
 | 
			
		||||
        for jira_project in jira_client.projects():
 | 
			
		||||
            logger.debug(f"Searching Project: {jira_project.key}")
 | 
			
		||||
            proj = ProjectTracker(jira_client, jira_project.key)
 | 
			
		||||
            issues = sorted(proj.this_weeks_issues(), key=lambda issue: issue.status)
 | 
			
		||||
            all_issues = all_issues + issues
 | 
			
		||||
            for issue in issues:
 | 
			
		||||
                if issue.status == "Done":
 | 
			
		||||
                    points = points + float(issue.points)
 | 
			
		||||
 | 
			
		||||
        for issue in all_issues:
 | 
			
		||||
            print(row_format.format(issue.name, issue.summary, issue.points, issue.status))
 | 
			
		||||
        print(f"\nTotal points this week: {points}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    except (Exception) as e:
 | 
			
		||||
        logger.critical(e)
 | 
			
		||||
        if args.debug:
 | 
			
		||||
            tb = sys.exc_info()[2]
 | 
			
		||||
            traceback.print_tb(tb)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										77
									
								
								jira_tracker/jira_auth.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								jira_tracker/jira_auth.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,77 @@
 | 
			
		||||
from jira_tracker.logger import logger
 | 
			
		||||
import jira, yaml
 | 
			
		||||
import pathlib, os
 | 
			
		||||
 | 
			
		||||
class JiraAuth:
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.config = None
 | 
			
		||||
 | 
			
		||||
        # Intialize config
 | 
			
		||||
        self.load_config(self.config_location)
 | 
			
		||||
 | 
			
		||||
        if not "token" in self.config:
 | 
			
		||||
            self.stdin_configure()
 | 
			
		||||
            self.update_config(self.config_location)
 | 
			
		||||
        
 | 
			
		||||
        logger.debug("Successfully intialized JiraAuth!")
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    def load_config(self, config_file):
 | 
			
		||||
        self.config = {}
 | 
			
		||||
        logger.debug(f"Loading config from: {config_file}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if self.config_location.exists():
 | 
			
		||||
            data = None
 | 
			
		||||
 | 
			
		||||
            # Load config file
 | 
			
		||||
            with open(config_file) as f:
 | 
			
		||||
                data = yaml.load(f, Loader=yaml.SafeLoader)
 | 
			
		||||
            
 | 
			
		||||
            # Update config with config data
 | 
			
		||||
            for key in data:
 | 
			
		||||
                self.config[key] = data[key]
 | 
			
		||||
        else:
 | 
			
		||||
            logger.warning(f"Config does not exist at: {config_file}")
 | 
			
		||||
 | 
			
		||||
    def update_config(self, config_file):
 | 
			
		||||
        if not config_file.exists():
 | 
			
		||||
            config_file.parent.mkdir(parents=True)
 | 
			
		||||
 | 
			
		||||
        with open(config_file, 'w') as f:
 | 
			
		||||
            data = yaml.dump(self.config, f)
 | 
			
		||||
 | 
			
		||||
    def stdin_configure(self):
 | 
			
		||||
 | 
			
		||||
        # Clear keys that need new inputs
 | 
			
		||||
        for key in ["server", "user", "token"]:
 | 
			
		||||
            self.config[key] = ""
 | 
			
		||||
 | 
			
		||||
        # Prompt sever
 | 
			
		||||
        print("Please enter the jira server to interface with")
 | 
			
		||||
        print("eg. jira.atlassian.com")
 | 
			
		||||
        while not "server" in self.config or self.config["server"] == "":
 | 
			
		||||
            self.config["server"] = input("Server: ")
 | 
			
		||||
 | 
			
		||||
        # Prompt Username
 | 
			
		||||
        print("Please enter your username")
 | 
			
		||||
        print("Example: user@domain.tld")
 | 
			
		||||
        while not "user" in self.config or self.config["user"] == "":
 | 
			
		||||
            self.config["user"] = input("Username: ")
 | 
			
		||||
 | 
			
		||||
        # Prompt Token
 | 
			
		||||
        print("Please generate a token and enter it here")
 | 
			
		||||
        print("https://id.atlassian.com/manage-profile/security/api-tokens")
 | 
			
		||||
        while not "token" in self.config or self.config["token"] == "":
 | 
			
		||||
            self.config["token"] = input("Token: ")
 | 
			
		||||
 | 
			
		||||
        if not "points_field" in self.config:
 | 
			
		||||
            self.config["points_field"] = "customfield_10016"
 | 
			
		||||
 | 
			
		||||
    def get_client(self):
 | 
			
		||||
        return jira.JIRA(self.config["server"], basic_auth=(self.config["user"], self.config["token"]))
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def config_location(self):
 | 
			
		||||
        return pathlib.Path(str(pathlib.Path.home()), ".jira-tracker", "config.yaml")
 | 
			
		||||
							
								
								
									
										16
									
								
								jira_tracker/logger.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								jira_tracker/logger.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
logger.setLevel(logging.DEBUG)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ch = logging.StreamHandler()
 | 
			
		||||
ch.setLevel(logging.INFO)
 | 
			
		||||
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
 | 
			
		||||
ch.setFormatter(formatter)
 | 
			
		||||
 | 
			
		||||
logger.addHandler(ch)
 | 
			
		||||
 | 
			
		||||
def enable_debug_logger():
 | 
			
		||||
    logger.setLevel(logging.DEBUG)
 | 
			
		||||
    ch.setLevel(logging.DEBUG)
 | 
			
		||||
							
								
								
									
										20
									
								
								jira_tracker/project_tracker.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								jira_tracker/project_tracker.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
from jira_tracker.logger import logger
 | 
			
		||||
from jira_tracker.tracker_issue import TrackerIssue
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
class ProjectTracker:
 | 
			
		||||
    def __init__(self, jira_client, project_key):
 | 
			
		||||
        self.jira = jira_client
 | 
			
		||||
        self.key = project_key
 | 
			
		||||
    
 | 
			
		||||
    def this_weeks_issues(self):
 | 
			
		||||
        result = self.jira.search_issues(
 | 
			
		||||
            f"project = {self.key} AND assignee = currentuser() AND ((resolutiondate >= -{datetime.datetime.today().weekday()}d AND status = Done) OR status != Done)"
 | 
			
		||||
        )
 | 
			
		||||
        logger.debug(f"Found {len(result)} valid records this week in {self.key}")
 | 
			
		||||
 | 
			
		||||
        issues = []
 | 
			
		||||
        for issue in result:
 | 
			
		||||
            issues.append(TrackerIssue(issue))
 | 
			
		||||
 | 
			
		||||
        return issues
 | 
			
		||||
							
								
								
									
										21
									
								
								jira_tracker/tracker_issue.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								jira_tracker/tracker_issue.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
from jira_tracker.logger import logger
 | 
			
		||||
 | 
			
		||||
class TrackerIssue:
 | 
			
		||||
    def __init__(self, jira_issue):
 | 
			
		||||
        self.data = jira_issue
 | 
			
		||||
    
 | 
			
		||||
    @property
 | 
			
		||||
    def name(self):
 | 
			
		||||
        return str(self.data)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def summary(self):
 | 
			
		||||
        return str(self.data.fields.summary)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def status(self):
 | 
			
		||||
        return str(self.data.fields.status)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def points(self):
 | 
			
		||||
        return str(self.data.fields.customfield_10016)
 | 
			
		||||
		Reference in New Issue
	
	Block a user