def __init__(self, parser): ''' Constructor ''' self.parser = parser log.info(self.__class__.__name__ + " initialized") try: # Input File self.input_file = parser.options.input_file # Estimate To Complete self.estimate_to_complete = parser.options.estimate_to_complete # Time spent _effort_actual_md = 0.0 # Check if input file exists if check_file_exists(self.input_file) == 1: die("File '" + self.input_file + "' doesn't exist. Fatal.") self.euro_sign_encoded = u" \u20AC" self.euro = " eur" self.project_name = read_property_from_file("project_name", "project", self.input_file) self.baseline_md = read_property_from_file("baseline_md", "project", self.input_file) self.date_format = read_property_from_file("date_format", "project", self.input_file) # Datelimit self.date_limit = None if parser.options.date_limit is not None: self.date_limit = datetime.strptime(parser.options.date_limit, self.date_format) + timedelta(hours=23, minutes=59, seconds=59) # Project related values self.kick_off_date = datetime.strptime( read_property_from_file("kick_off_date", "project", self.input_file), self.date_format).date() self.uat_start_baseline = datetime.strptime( read_property_from_file("uat_start_baseline", "project", self.input_file), self.date_format).date() self.uat_start_actual = datetime.strptime( read_property_from_file("uat_start_actual", "project", self.input_file), self.date_format).date() self.go_live_baseline = datetime.strptime( read_property_from_file("go_live_baseline", "project", self.input_file), self.date_format).date() self.go_live_actual = datetime.strptime( read_property_from_file("go_live_actual", "project", self.input_file), self.date_format).date() self.issue_jql = list(ast.literal_eval(read_property_from_file("issue_jql", "project", self.input_file))) self.output_path = read_property_from_file("output_path", "project", self.input_file) self.output_filename = read_property_from_file("output_filename", "project", self.input_file) # Add the date limit in the filename if self.date_limit is not None: self.output_location_datelimit = str(self.output_path + "latest_DL" + self.date_limit.strftime("%Y%m%d") + "_" + self.output_filename) else: # Add "latest" in the filename self.output_location_latest = str(self.output_path + "latest_" + self.output_filename) self.revenue_offer = read_property_from_file("revenue_offer", "project", self.input_file) self.md_rate_offer = read_property_from_file("md_rate_offer", "project", self.input_file) self.md_rate_internal = read_property_from_file("md_rate_internal", "project", self.input_file) self.other_costs_baseline = read_property_from_file("other_costs_baseline", "project", self.input_file) self.other_costs_actual = read_property_from_file("other_costs_actual", "project", self.input_file) jira = jira_authenticate(parser.options.jiraURL, parser.options.jiraUsername, parser.options.jiraPassword) log.info("--------------------------------------------------------") log.info("| " + self.project_name) log.info("--------------------------------------------------------") log.info("Kick-off : " + str(self.kick_off_date)) log.info("UAT Start (Baseline) : " + str(self.uat_start_baseline)) log.info("UAT Start (Actual) : " + str(self.uat_start_actual)) log.info("GoLive (Baseline) : " + str(self.go_live_baseline)) log.info("GoLive (Actual) : " + str(self.go_live_actual)) log.info("Effort (Baseline) : " + str(self.baseline_md) + " md") ############################################# # TIME SPENT ############################################# _effort_spent_in_future_sec = 0.0 # Iterate JQL Filters for f in self.issue_jql: log.debug("Processing JQL: " + f) r = jira.search_issues(f, 0, False) # Iterate Issues in each JQL for k in r: # Get each issue from filter issue = jira.issue(k) # log.debug("Working on issue: " + issue.key) # Iterate Workogs in each Issue for worklog in jira.worklogs(issue.key): # log.debug(issue.key + ": " + str(worklog.id)) # pprint (vars(worklog)) # Get datetime that the worklog is about _started = datetime.strptime(worklog.started[:10], "%Y-%m-%d") # Check entries against date limit from the command line if self.date_limit is not None and _started <= self.date_limit: log.debug( "Issue [" + str(issue.key) + "] Worklog [" + str(worklog.id) + "] with date " + str( _started) + " will be counted because date limit is " + str(self.date_limit)) _effort_actual_md = _effort_actual_md + worklog.timeSpentSeconds elif self.date_limit is not None and _started > self.date_limit: log.warn( "Issue [" + str(issue.key) + "] Worklog [" + str(worklog.id) + "] with date " + str( _started) + " will be added to EFFORT REMAINING because date limit is " + str( self.date_limit)) _effort_spent_in_future_sec = _effort_spent_in_future_sec + worklog.timeSpentSeconds elif self.date_limit is None: log.debug( "Issue [" + str(issue.key) + "] Worklog [" + str(worklog.id) + "] with date " + str( _started) + " will be counted because date limit hasn't been provided") _effort_actual_md = _effort_actual_md + worklog.timeSpentSeconds # Get issue's timespent in seconds and add it to the overall sum # if issue.fields.timespent is not None: # _effort_actual_md = _effort_actual_md + issue.fields.timespent log.debug("Time spent so far is : " + str(("%.2f" % ((_effort_actual_md / 3600) / 8)))) # Switch timespent to md and round it off to 2 digits _effort_actual_md = "%.2f" % ((_effort_actual_md / 3600) / 8) log.info("Effort (Actual) : " + str(_effort_actual_md) + " md") ############################################# # ESTIMATE TO COMPLETE ############################################# _effort_remaining_md = 0.0 # if float(_effort_actual_md) > float(self.baseline_md) and self.estimate_to_complete is None: die("Time spent " + str( _effort_actual_md) + " md is higher than the baseline " + self.baseline_md + " md so an estimate to complete calculation cannot take place, please use -e switch to provide a manual E.t.C.") elif self.estimate_to_complete is None: _effort_remaining_md = _effort_remaining_md + (float(self.baseline_md) - float(_effort_actual_md)) else: _effort_remaining_md = ((_effort_spent_in_future_sec / 3600) / 8) + float(self.estimate_to_complete) log.info("Effort (Remaining) : " + str("%.2f" % _effort_remaining_md) + " md") if _effort_spent_in_future_sec > 0.0: log.warn("(Effort remaining contains time spent in the future: " + "%.2f" % ( (_effort_spent_in_future_sec / 3600) / 8) + " md)") ############################################# # EFFORT AT COMPLETION ############################################# # Calculate Estimate At Completion _effort_at_completion_md = float(_effort_actual_md) + float(_effort_remaining_md) log.info("Effort (At Completion) : " + str(_effort_at_completion_md) + " md") ############################################# # ON TIME ############################################# _a = self.go_live_actual - self.kick_off_date _b = self.go_live_baseline - self.kick_off_date # On Time _on_time = (_a.total_seconds() / _b.total_seconds()) ############################################# # IN EFFORT ############################################# # In Effort _in_effort = _effort_at_completion_md / float(self.baseline_md) ############################################# # BUDGET ############################################# log.info("Revenue : " + str(self.revenue_offer) + self.euro_sign_encoded) log.info("md Rate (Offer) : " + str(self.md_rate_offer) + self.euro_sign_encoded) log.info("md Rate (Internal) : " + str(self.md_rate_internal) + self.euro_sign_encoded) _md_cost_baseline = float(self.md_rate_internal) * float(self.baseline_md) log.info("md Cost (Baseline) : " + str(_md_cost_baseline) + self.euro_sign_encoded) _md_cost_eac = float(self.md_rate_internal) * float(_effort_at_completion_md) log.info("md Cost (At Completion) : " + str(_md_cost_eac) + self.euro_sign_encoded) log.info("Other Costs (Baseline) : " + str(self.other_costs_baseline) + self.euro_sign_encoded) log.info("Other Costs (Actual) : " + str(self.other_costs_actual) + self.euro_sign_encoded) _pnl_baseline = ((float(self.revenue_offer) - float(_md_cost_baseline) - float( self.other_costs_baseline)) / float(self.revenue_offer)) * 100 log.info("PnL (Baseline) : " + str("%.2f" % _pnl_baseline) + "%") _pnl_eac = ((float(self.revenue_offer) - float(_md_cost_eac) - float(self.other_costs_actual)) / float( self.revenue_offer)) * 100 log.info("PnL (At Completion) : " + str("%.2f" % _pnl_eac) + "%") ############################################# # IN BUDGET ############################################# _in_budget = 1 + (float(_pnl_baseline / 100) - float(_pnl_eac / 100)) log.info("--------------------------------------------------------") log.info("On Time : " + str("%.2f" % _on_time)) log.info("In Effort : " + str("%.2f" % _in_effort)) log.info("In Budget : " + str("%.2f" % _in_budget)) log.info("--------------------------------------------------------") html_code = self.export_to_html(self.project_name, self.kick_off_date.strftime(self.date_format), self.uat_start_baseline.strftime(self.date_format), self.uat_start_actual.strftime(self.date_format), self.go_live_baseline.strftime(self.date_format), self.go_live_actual.strftime(self.date_format), "%.2f" % _on_time, self.baseline_md, _effort_actual_md, _effort_remaining_md, _effort_at_completion_md, "%.2f" % _in_effort, str(self.revenue_offer) + self.euro, str(self.md_rate_offer) + self.euro, str(self.md_rate_internal) + self.euro, str(_md_cost_baseline) + self.euro, str(_md_cost_eac) + self.euro, str(self.other_costs_baseline) + self.euro, str(self.other_costs_actual) + self.euro, str("%.2f" % _pnl_baseline) + "%", str("%.2f" % _pnl_eac) + "%", str("%.2f" % _in_budget), str(" ".join(sys.argv))) # Output in either location if self.date_limit is not None: with open(self.output_location_datelimit, "w") as text_file: text_file.write(html_code) log.debug("Output added to " + self.output_location_datelimit) else: with open(self.output_location_latest, "w") as text_file: text_file.write(html_code) log.debug("Output added to " + self.output_location_latest) except: raise
timestamp_file = parser.options.path + properties.osDirSeparator + properties.timeStampFilename skip_files = [] start_time = time.time() if parser.options.path == os.getcwd() and (parser.options.install or parser.options.skip or parser.options.profile): die("You tried to run espedite from within its own folder. Please cd to your code folder instead and run it from there." ) # Remove any compiled files remove_files_by_ext_recursively(parser.options.path, properties.binaryCodeExtension) # Read timestamp if check_file_exists(timestamp_file): with open(timestamp_file, 'r') as f: timestamp = f.readline().strip() log.debug("Last execution was on {} (UNIX Timestamp: {}) ".format( timestamp_to_human_readable(timestamp), str(timestamp))) log.info("Running script in path '{}'".format(parser.options.path)) check_executable_exists("ampy", True) if parser.options.connect: check_executable_exists("picocom", True) modified_relative_files = get_modified_files(parser.options.path, timestamp, True) if parser.options.skip:
sys.exit() # Parse arguments (options, args) = parser.parse_args() # If Jira passsword prompt is requested, then prompt if options.promptForJiraPassword: log.info("Enter your JIRA password for " + options.jiraUsername + "@" + options.jiraURL + ": ") options.jiraPassword = getpass.getpass("> ") # Make sure all mandatory options are provided for m in mandatory_options: if not options.__dict__[m]: log.critical("Mandatory option '" + m + "' is missing\n") parser.print_help() sys.exit() # Make sure all mandatory file_options exist for f in file_options: if check_file_exists(options.__dict__[f]): log.critical("The following file is missing '" + options.__dict__[f] +"'\n") parser.print_help() sys.exit() # Set logging level if options.verbose == 1: log.root.handlers[0].setLevel(logging.DEBUG) elif options.verbose == 2: log.root.handlers[0].setLevel(logging.DEBUG) # same logging level as verbose BUT its value also controls the logIfVerbose method