diff --git a/gitfiti.py b/gitfiti.py index 1acb0521d8..0df3035dd2 100755 --- a/gitfiti.py +++ b/gitfiti.py @@ -10,10 +10,12 @@ """ from datetime import datetime, timedelta +from collections import defaultdict import itertools import json import math import os +import re try: # Python 3+ from urllib.error import HTTPError, URLError @@ -193,6 +195,23 @@ } +def get_start_date(): + """returns a datetime object for the first sunday after one year ago today + at 12:00 noon""" + today = datetime.today() + date = datetime(today.year - 1, today.month, today.day, 12) + weekday = datetime.weekday(date) + + while weekday < 6: + date = date + timedelta(1) + weekday = datetime.weekday(date) + + return date + + +# get start date only once, in case program run between two days +start_date = get_start_date() + def str_to_sprite(content): # Break out lines and filter any excess lines = content.split('\n') @@ -293,19 +312,24 @@ def retrieve_contributions_calendar(username, base_url): def parse_contributions_calendar(contributions_calendar): - """Yield daily counts extracted from the contributions SVG.""" - for line in contributions_calendar.splitlines(): - for day in line.split(): - if 'data-count=' in day: - commit = day.split('=')[1] - commit = commit.strip('"') - yield int(commit) + """convert XML of contributions calendar to a dict {date: nubmer of commits}""" + data_count_pattern = re.compile('data-count="([\d]+)"') + data_date_pattern = re.compile('data-date="([-\d]+)"') + elements = re.findall("]+>", contributions_calendar) + result = defaultdict(lambda: 0) + for element in elements: + try: + data_count = int(data_count_pattern.search(element).group(1)) + data_date = data_date_pattern.search(element).group(1) + result[data_date] = data_count + except: + pass + return result def find_max_daily_commits(contributions_calendar): """finds the highest number of commits in one day""" - daily_counts = parse_contributions_calendar(contributions_calendar) - return max(daily_counts) + return max(contributions_calendar.values()) def calculate_multiplier(max_commits): @@ -320,20 +344,6 @@ def calculate_multiplier(max_commits): return m -def get_start_date(): - """returns a datetime object for the first sunday after one year ago today - at 12:00 noon""" - today = datetime.today() - date = datetime(today.year - 1, today.month, today.day, 12) - weekday = datetime.weekday(date) - - while weekday < 6: - date = date + timedelta(1) - weekday = datetime.weekday(date) - - return date - - def generate_next_dates(start_date, offset=0): """generator that returns the next date, requires a datetime object as input. The offset is in weeks""" @@ -367,8 +377,9 @@ def commit(commitdate, shell): return template.format(commitdate.isoformat(), commitdate.isoformat()) -def fake_it(image, start_date, username, repo, git_url, shell, offset=0, multiplier=1): - template_bash = ( +def fake_it(image, start_date, username, repo, git_url, shell, offset=0, multiplier=1, + contributions_calendar=defaultdict(lambda: 0)): + template = ( '#!/usr/bin/env bash\n' 'REPO={0}\n' 'git init $REPO\n' @@ -403,9 +414,10 @@ def fake_it(image, start_date, username, repo, git_url, shell, offset=0, multipl template = template_bash if shell == 'bash' else template_powershell strings = [] - for value, date in zip(generate_values_in_date_order(image, multiplier), + for commits_need, date in zip(generate_values_in_date_order(image, multiplier), generate_next_dates(start_date, offset)): - for _ in range(value): + commits_now = contributions_calendar[date.strftime('%Y-%m-%d')] + for _ in range(commits_need - commits_now): strings.append(commit(date, shell)) return template.format(repo, ''.join(strings), git_url, username) @@ -435,6 +447,8 @@ def main(): contributions_calendar = retrieve_contributions_calendar(username, git_base) + contributions_calendar = parse_contributions_calendar(contributions_calendar) + max_daily_commits = find_max_daily_commits(contributions_calendar) m = calculate_multiplier(max_daily_commits) @@ -481,7 +495,6 @@ def main(): except: image = IMAGES[image_name_fallback] - start_date = get_start_date() fake_it_multiplier = m * match if not ghe: @@ -495,7 +508,7 @@ def main(): 'Enter the target shell ({}): '.format(' or '.join(SHELLS.keys()))) output = fake_it(image, start_date, username, repo, git_url, shell, offset, - fake_it_multiplier) + fake_it_multiplier, contributions_calendar) output_filename = 'gitfiti.{}'.format(SHELLS[shell]) save(output, output_filename) diff --git a/tests/test_find_max_daily_commits.py b/tests/test_find_max_daily_commits.py index d8950db2e8..caf0e885a4 100644 --- a/tests/test_find_max_daily_commits.py +++ b/tests/test_find_max_daily_commits.py @@ -72,18 +72,48 @@ def test_parse_contributions_calendar(): - expected = [ - 0, 0, 0, 0, 6, 0, 0, - 0, 0, 0, 0, 0, 0, 6, - 84, 16, 4, 8, 0, 0, 0, - 0, 25, 66, 20, 10, 0, 0, - 33, 9, 0, 0, 7, - ] + expected = { + "2016-05-08": 0, + "2016-05-09": 0, + "2016-05-10": 0, + "2016-05-11": 0, + "2016-05-12": 6, + "2016-05-13": 0, + "2016-05-14": 0, + "2016-05-15": 0, + "2016-05-16": 0, + "2016-05-17": 0, + "2016-05-18": 0, + "2016-05-19": 0, + "2016-05-20": 0, + "2016-05-21": 6, + "2016-05-22": 84, + "2016-05-23": 16, + "2016-05-24": 4, + "2016-05-25": 8, + "2016-05-26": 0, + "2016-05-27": 0, + "2016-05-28": 0, + "2016-05-29": 0, + "2016-05-30": 25, + "2016-05-31": 66, + "2016-06-01": 20, + "2016-06-02": 10, + "2016-06-03": 0, + "2016-06-04": 0, + "2016-06-05": 33, + "2016-06-06": 9, + "2016-06-07": 0, + "2016-06-08": 0, + "2016-06-09": 7, + } actual = parse_contributions_calendar(CONTRIBUTIONS_CALENDAR_SVG) - assert list(actual) == expected + assert sorted(actual.keys()) == sorted(expected.keys()) + assert all(actual[k] == expected[k] for k in actual.keys()) def test_find_max_daily_commits(): - assert find_max_daily_commits(CONTRIBUTIONS_CALENDAR_SVG) == 84 + contributions_calendar = parse_contributions_calendar(CONTRIBUTIONS_CALENDAR_SVG) + assert find_max_daily_commits(contributions_calendar) == 84