Example #1
0
def plot_prs_merged(created_ats, prs, repository):
    """Plot stats on merged PRs."""
    init_year = min(created_ats).year
    curr_year = datetime_parser('TODAY').year

    start_end_years = {}
    for year in range(init_year, curr_year + 1):
        start_year = datetime_parser('%s-01-01' % year)
        end_year = datetime_parser('%s-12-31 23:59:59' % year)
        start_end_years[year] = (start_year, end_year)
        print((year, len([x for x in created_ats if x >= start_year and x <= end_year])))

    prs_by_year = {}
    for (created_at, pr) in zip(created_ats, prs):
        for year, (start_year, end_year) in start_end_years.items():
            if created_at >= start_year and created_at <= end_year:
                prs_by_year.setdefault(year, []).append(pr)

    gh_logins = ['boegel', 'verdurin', 'pescobar', 'vanzod', 'wpoely86', 'JensTimmerman', 'migueldiascosta']
    maintainers = ['boegel', 'verdurin', 'pescobar', 'vanzod', 'wpoely86', 'migueldiascosta', 'akesandgren',
                   'BartOldeman', 'damianam', 'ocaisa', 'Micket', 'zao', 'smoors', 'lexming',
                   'casparvl', 'branfosj']
    # (+ wpoely86 in 2016...)
    hpcugent = ['JensTimmerman', 'Caylo', 'stdweird', 'itkovian', 'piojo', 'hpcugent', 'nudded', 'boegel']
    gh_logins_bis = gh_logins + ['hajgato', 'fgeorgatos', 'RvDijk', 'JackPerdue', 'smoors', 'geimer', 'SimonPinches']
    gh_logins_bis += ['Helios07', 'cstackpole', 'akesandgren', 'rubendibattista', 'BartOldeman', 'damianam', 'ocaisa',
                      'stdweird', 'nudded', 'piojo', 'Caylo', 'hpcugent', 'Darkless012', 'zarybnicky', 'deniskristak']

    for year in sorted(prs_by_year.keys()):
        prs_cnt = len(prs_by_year[year])
        prs_cnt_maintainers = len([pr for pr in prs_by_year[year] if pr['user']['login'] in maintainers])
        prs_cnt_hpcugent = len([pr for pr in prs_by_year[year] if pr['user']['login'] in hpcugent])
        prs_cnt_by = {}
        for gh_login in gh_logins_bis:
            prs_cnt_by[gh_login] = len([pr for pr in prs_by_year[year] if pr['user']['login'] == gh_login])

        merged_prs = [pr for pr in prs_by_year[year] if pr.get('is_merged', False)]
        merged_cnt = len(merged_prs)
        merged_cnt_by = {}
        for gh_login in gh_logins:
            merged_cnt_by[gh_login] = len([pr for pr in merged_prs if pr['merged_by']['login'] == gh_login])

        closed_cnt = len([pr for pr in prs_by_year[year] if pr['state'] == 'closed'])
        open_cnt = len([pr for pr in prs_by_year[year] if pr['state'] == 'open'])

        print('* %s: %s PRs' % (year, prs_cnt))
        print('* %s unique contributors' % len(nub(pr['user']['login'] for pr in prs_by_year[year])))
        print('* PRs by maintainers: %s' % prs_cnt_maintainers)
        print('* PRs by HPC-UGent: %s' % prs_cnt_hpcugent)
        for gh_login in gh_logins_bis:
            print('- PRs by %s: ' % gh_login, prs_cnt_by[gh_login])
        print('- merged: ', merged_cnt)
        for gh_login in gh_logins:
            print('- merged by %s: ' % gh_login, merged_cnt_by[gh_login])
        print('- closed: ', closed_cnt - merged_cnt)
        print('- open: ', open_cnt)
        new_pr_tag = "created using `eb --new-pr`"
        print('- opened with --new-pr: ', len([pr for pr in prs_by_year[year] if new_pr_tag in (pr['body'] or '')]))
        print('')
Example #2
0
def plot_pr_stats(prs, go):
    """ Create plot overview of prs, save in pdf format"""
    created_ats = [datetime_parser(pr['created_at'].split('T')[0]) for pr in prs]
    closed_ats = [datetime_parser((pr['closed_at'] or 'T').split('T')[0] or 'ENDNEXTMONTH') for pr in prs]
    authors = [pr['user']['login'] for pr in prs]

    print('Plotting...')
    plot_historic_PR_ages(created_ats, closed_ats, go.options.repository)
    plot_open_closed_PRs(created_ats, closed_ats, go.options.repository)
    plot_prs_by_author(created_ats, authors, go.options.repository)
    print_prs_uniq_authors(created_ats, authors, go.options.repository)
    plot_prs_merged(created_ats, prs, go.options.repository)
Example #3
0
    def test_datetime_parser(self):
        """Test the date_parser"""
        testdate = datetime.datetime(1970, 1, 1)
        self.assertEqual(datetime_parser('1970-01-01') , testdate)
        self.assertEqual(datetime_parser('1970-1-1'), testdate)

        today = datetime.datetime.today()
        beginthismonth = datetime.datetime(today.year, today.month, 1, 12, 1)
        self.assertEqual(datetime_parser('BEGINTHISMONTH 12:1') , beginthismonth)

        endapril = datetime.datetime(today.year, 4, 30, 12, 1, 1, 1)
        self.assertEqual(datetime_parser('ENDAPRIL 12:01:01.000001') , endapril)
Example #4
0
    def test_datetime_parser(self):
        """Test the date_parser"""
        testdate = datetime.datetime(1970, 1, 1)
        self.assertEqual(datetime_parser('1970-01-01') , testdate)
        self.assertEqual(datetime_parser('1970-1-1'), testdate)

        today = datetime.datetime.today()
        beginthismonth = datetime.datetime(today.year, today.month, 1, 12, 1)
        self.assertEqual(datetime_parser('BEGINTHISMONTH 12:1') , beginthismonth)

        endapril = datetime.datetime(today.year, 4, 30, 12, 1, 1, 1)
        self.assertEqual(datetime_parser('ENDAPRIL 12:01:01.000001') , endapril)
Example #5
0
def plot_historic_PR_ages(created_ats, closed_ats, repository):
    """Plot historic PR ages."""
    day = min(created_ats)
    days = []
    ages, ages_all, ages_rev = [], [], []
    while day <= datetime_parser('TODAY') + ONE_DAY:
        days.append(day)

        open_counts = [0]*(len(GROUPS)+1)
        for idx in range(0, len(created_ats)):
            if created_ats[idx] <= day and closed_ats[idx] > day:
                for i, grp in enumerate(GROUPS + [ENDGROUP]):
                    if day - created_ats[idx] < grp:
                        open_counts[i] += 1
                        break
        ages.append(open_counts[::-1])
        ages_rev.append(open_counts[:])
        open_counts.append(sum(open_counts))
        ages_all.append(open_counts[::-1])

        day += ONE_DAY

    print("%s: open = %s" % (days[-1], open_counts[-1]))

    days = pd.to_datetime(days)

    pd_df_all = pd.DataFrame(ages_all, days, columns=['all']+GROUP_LABELS[::-1]).sort_index().fillna(method='ffill')
    res = pd_df_all.plot(kind='area', stacked=False, title="open %s PRs, by age" % repository)
    res.legend(ncol=len(GROUP_LABELS)+1, fontsize='small')
    plt.savefig('%s_PR_stats_all' % repository)

    res = pd_df_all.plot(kind='area', stacked=False, title="open %s PRs, by age (zoomed)" % repository)
    res.set_ylim([0, 50])
    res.legend(ncol=len(GROUP_LABELS)+1, fontsize='small')
    plt.savefig('%s_PR_stats_all_zoomed' % repository)

    pd_df = pd.DataFrame(ages, days, columns=GROUP_LABELS[::-1]).sort_index().fillna(method='ffill')
    res = pd_df.plot(kind='area', stacked=True, title="open %s PRs, by age (stacked)" % repository)
    res.legend(ncol=len(GROUP_LABELS), fontsize='small')
    plt.savefig('%s_PR_stats_all_stacked' % repository)

    pd_df_all_year = pd_df_all.loc[LAST_YEAR:]
    res = pd_df_all_year.plot(kind='area', stacked=False, title="open %s PRs, by age (last year)" % repository)
    res.legend(ncol=len(GROUP_LABELS)+1, fontsize='small')
    plt.savefig('%s_PR_stats_year' % repository)

    pd_df_all_month = pd_df_all.loc[LAST_MONTH:]
    res = pd_df_all_month.plot(kind='area', stacked=False, title="open %s PRs, by age (last month)" % repository)
    res.legend(ncol=len(GROUP_LABELS)+1, fontsize='small')
    plt.savefig('%s_PR_stats_month' % repository)

    pd_df = pd.DataFrame(ages_rev, days, columns=GROUP_LABELS).sort_index().fillna(method='ffill')
    res = pd_df.plot(kind='area', stacked=True, title="open %s PRs, by age (stacked)" % repository)
    res.legend(ncol=len(GROUP_LABELS), fontsize='small')
    plt.savefig('%s_PR_stats_all_stacked_rev' % repository)

    res = pd_df.plot(kind='area', stacked=True, title="open %s PRs, by age (stacked, zoomed)" % repository)
    res.set_ylim([0, 50])
    res.legend(ncol=len(GROUP_LABELS), fontsize='small')
    plt.savefig('%s_PR_stats_all_stacked_rev_zoomed' % repository)
Example #6
0
def plot_historic_PR_ages(created_ats, closed_ats, repository):
    """Plot historic PR ages."""
    day = min(created_ats)
    days = []
    ages, ages_all, ages_rev = [], [], []
    while day <= datetime_parser("TODAY"):
        days.append(day)

        open_counts = [0] * (len(GROUPS) + 1)
        for idx in xrange(0, len(created_ats)):
            if created_ats[idx] <= day and closed_ats[idx] > day:
                for i, grp in enumerate(GROUPS + [ENDGROUP]):
                    if day - created_ats[idx] < grp:
                        open_counts[i] += 1
                        break
        ages.append(open_counts[::-1])
        ages_rev.append(open_counts[:])
        open_counts.append(sum(open_counts))
        ages_all.append(open_counts[::-1])

        day += ONE_DAY

    pd_df_all = pd.DataFrame(ages_all, days, columns=["all"] + GROUP_LABELS[::-1]).sort().fillna(method="ffill")
    res = pd_df_all.plot(kind="area", stacked=False, title="open %s PRs, by age" % repository)
    res.legend(ncol=len(GROUP_LABELS) + 1, fontsize="small")
    plt.savefig("%s_PR_stats_all" % repository)

    res = pd_df_all.plot(kind="area", stacked=False, title="open %s PRs, by age (zoomed)" % repository)
    res.set_ylim([0, 50])
    res.legend(ncol=len(GROUP_LABELS) + 1, fontsize="small")
    plt.savefig("%s_PR_stats_all_zoomed" % repository)

    pd_df = pd.DataFrame(ages, days, columns=GROUP_LABELS[::-1]).sort().fillna(method="ffill")
    res = pd_df.plot(kind="area", stacked=True, title="open %s PRs, by age (stacked)" % repository)
    res.legend(ncol=len(GROUP_LABELS), fontsize="small")
    plt.savefig("%s_PR_stats_all_stacked" % repository)

    pd_df_all_year = pd_df_all.select(lambda d: d > LAST_YEAR)
    res = pd_df_all_year.plot(kind="area", stacked=False, title="open %s PRs, by age (last year)" % repository)
    res.legend(ncol=len(GROUP_LABELS) + 1, fontsize="small")
    plt.savefig("%s_PR_stats_year" % repository)

    pd_df_all_month = pd_df_all.select(lambda d: d > LAST_MONTH)
    res = pd_df_all_month.plot(kind="area", stacked=False, title="open %s PRs, by age (last month)" % repository)
    res.legend(ncol=len(GROUP_LABELS) + 1, fontsize="small")
    plt.savefig("%s_PR_stats_month" % repository)

    pd_df = pd.DataFrame(ages_rev, days, columns=GROUP_LABELS).sort().fillna(method="ffill")
    res = pd_df.plot(kind="area", stacked=True, title="open %s PRs, by age (stacked)" % repository)
    res.legend(ncol=len(GROUP_LABELS), fontsize="small")
    plt.savefig("%s_PR_stats_all_stacked_rev" % repository)

    res = pd_df.plot(kind="area", stacked=True, title="open %s PRs, by age (stacked, zoomed)" % repository)
    res.set_ylim([0, 50])
    res.legend(ncol=len(GROUP_LABELS), fontsize="small")
    plt.savefig("%s_PR_stats_all_stacked_rev_zoomed" % repository)
Example #7
0
def main():
    opts = {
        "github-account": ("GitHub account where repository is located", None, "store", "hpcugent", "a"),
        "github-user": ("GitHub user to use (for authenticated access)", None, "store", "boegel", "u"),
        "repository": ("Repository to use", None, "store", "easybuild-easyconfigs", "r"),
    }
    go = simple_option(go_dict=opts, descr="Script to print overview of pull requests for a GitHub repository")

    pickle_file = None
    if go.args:
        pickle_file = go.args[0]

    prs = fetch_pr_data(pickle_file, go.options.github_user, go.options.github_account, go.options.repository)

    created_ats = [datetime_parser(pr["created_at"].split("T")[0]) for pr in prs]
    closed_ats = [datetime_parser((pr["closed_at"] or "T").split("T")[0] or "ENDNEXTMONTH") for pr in prs]

    print("Plotting...")
    plot_historic_PR_ages(created_ats, closed_ats, go.options.repository)
    plot_open_closed_PRs(created_ats, closed_ats, go.options.repository)
Example #8
0
def plot_prs_by_author(created_ats, authors, repository):
    """Plot overview of PR authors."""
    day = min(created_ats)
    days = []

    uniq_authors = nub(authors)
    print("Found %d unique PR authors for %s repository" % (len(uniq_authors), repository))
    author_counts = []

    while day <= datetime_parser('TODAY'):
        days.append(day)

        counts = [0] * len(uniq_authors)
        for idx in range(0, len(created_ats)):
            if created_ats[idx] <= day:
                for i, author in enumerate(uniq_authors):
                    if authors[idx] == author:
                        counts[i] += 1
                        break

        author_counts.append(counts)

        day += ONE_DAY

    # filter author counts, only show top 10 author, collapse remaining authors into 'other'
    sorted_author_counts = sorted(enumerate(author_counts[-1]), key=lambda x: x[1], reverse=True)
    top_idxs = [idx for (idx, _) in sorted_author_counts[:30]]
    other_idxs = [idx for idx in range(len(uniq_authors)) if idx not in top_idxs]

    plot_author_counts = []
    for day_counts in author_counts:
        plot_day_counts = []

        for idx in top_idxs[::-1]:
            plot_day_counts.append(day_counts[idx])

        other_day_count = 0
        for idx in other_idxs:
            other_day_count += day_counts[idx]
        plot_day_counts.append(other_day_count)

        plot_author_counts.append(plot_day_counts)

    plot_authors = []
    for idx in top_idxs[::-1]:
        plot_authors.append('%s (%d)' % (uniq_authors[idx], author_counts[-1][idx]))
    plot_authors.append('OTHER (%d)' % plot_author_counts[-1][-1])

    pd_df = pd.DataFrame(plot_author_counts, days, columns=plot_authors).sort_index().fillna(method='ffill')
    res = pd_df.plot(kind='area', stacked=True, title="%s PRs by author (stacked)" % repository)
    res.legend(ncol=2, fontsize='small', loc='best')
    plt.savefig('%s_PR_per_author_stacked' % repository)
Example #9
0
    def take_action(self, action, dest, opt, value, values, parser):
        """extended take_action"""
        orig_action = action  # keep copy

        if action == 'shorthelp':
            parser.print_shorthelp()
            parser.exit()
        elif action in ('store_true', 'store_false', 'store_debuglog'):
            if action == 'store_debuglog':
                action = 'store_true'

            if opt.startswith("--%s-" % self.ENABLE):
                # keep action
                pass
            elif opt.startswith("--%s-" % self.DISABLE):
                # reverse action
                if action in ('store_true', 'store_debuglog'):
                    action = 'store_false'
                elif action in ('store_false', ):
                    action = 'store_true'

            if orig_action == 'store_debuglog' and action == 'store_true':
                setLogLevelDebug()

            Option.take_action(self, action, dest, opt, value, values, parser)
        elif action in self.EXTOPTION_EXTRA_OPTIONS:
            if action == "extend":
                # comma separated list convert in list
                lvalue = value.split(self.EXTEND_SEPARATOR)
                values.ensure_value(dest, []).extend(lvalue)
            elif action == "date":
                lvalue = date_parser(value)
                setattr(values, dest, lvalue)
            elif action == "datetime":
                lvalue = datetime_parser(value)
                setattr(values, dest, lvalue)
            else:
                raise (Exception(
                    "Unknown extended option action %s (known: %s)" %
                    (action, self.EXTOPTION_EXTRA_OPTIONS)))
        else:
            Option.take_action(self, action, dest, opt, value, values, parser)

        # set flag to mark as passed by action (ie not by default)
        # - distinguish from setting default value through option
        if hasattr(values, '_action_taken'):
            values._action_taken[dest] = True
    def take_action(self, action, dest, opt, value, values, parser):
        """Extended take_action"""
        orig_action = action  # keep copy

        if action == 'shorthelp':
            parser.print_shorthelp()
            parser.exit()
        elif action in ('store_true', 'store_false',) + self.EXTOPTION_LOG:
            if action in self.EXTOPTION_LOG:
                action = 'store_true'

            if opt.startswith("--%s-" % self.ENABLE):
                # keep action
                pass
            elif opt.startswith("--%s-" % self.DISABLE):
                # reverse action
                if action in ('store_true',) + self.EXTOPTION_LOG:
                    action = 'store_false'
                elif action in ('store_false',):
                    action = 'store_true'

            if orig_action in('store_debuglog', 'store_infolog', 'store_warninglog') and action == 'store_true':
                setLogLevel(orig_action.split('_')[1][:-3].upper())

            Option.take_action(self, action, dest, opt, value, values, parser)
        elif action in self.EXTOPTION_EXTRA_OPTIONS:
            if action == "extend":
                # comma separated list convert in list
                lvalue = value.split(self.EXTEND_SEPARATOR)
                values.ensure_value(dest, []).extend(lvalue)
            elif action == "date":
                lvalue = date_parser(value)
                setattr(values, dest, lvalue)
            elif action == "datetime":
                lvalue = datetime_parser(value)
                setattr(values, dest, lvalue)
            else:
                raise(Exception("Unknown extended option action %s (known: %s)" %
                                (action, self.EXTOPTION_EXTRA_OPTIONS)))
        else:
            Option.take_action(self, action, dest, opt, value, values, parser)

        # set flag to mark as passed by action (ie not by default)
        # - distinguish from setting default value through option
        if hasattr(values, '_action_taken'):
            values._action_taken[dest] = True
Example #11
0
    def test_datetime_parser(self):
        """Test the date_parser"""
        testdate = datetime.datetime(1970, 1, 1)
        self.assertEqual(datetime_parser('1970-01-01'), testdate)
        self.assertEqual(datetime_parser('1970-1-1'), testdate)

        today = datetime.datetime.today()
        todaytime = datetime.datetime(today.year, today.month, today.day)
        oneday = datetime.timedelta(days=1)

        self.assertEqual(datetime_parser('TODAY'), todaytime)
        self.assertEqual(datetime_parser('YESTERDAY'), todaytime - oneday)
        self.assertEqual(datetime_parser('TOMORROW'), todaytime + oneday)

        beginthismonth = datetime.datetime(today.year, today.month, 1, 12, 1)
        self.assertEqual(datetime_parser('BEGINTHISMONTH 12:1'),
                         beginthismonth)

        todayend = todaytime
        self.assertEqual(datetime_parser('TODAY BEGIN'), todaytime)
        self.assertEqual(datetime_parser('TODAY END'),
                         todaytime + oneday - datetime.timedelta(seconds=1))
        self.assertEqual(datetime_parser('YESTERDAY END'),
                         todaytime - datetime.timedelta(seconds=1))
Example #12
0
def plot_open_closed_PRs(created_ats, closed_ats, repository):
    """Plot open/closed PRs (in total) per day."""
    opened_closed = []
    days = []
    day = min(created_ats)
    while day <= datetime_parser('TODAY'):
        days.append(day)

        opened = sum([d.date() == day.date() for d in created_ats])
        closed = sum([d.date() == day.date() for d in closed_ats])
        open_cnt = opened - closed
        opened_closed.append((open_cnt, opened, closed))

        day += ONE_DAY

    pd_df = pd.DataFrame(opened_closed, days, columns=['open', 'opened', 'closed']).sort_index()
    res = pd_df.plot(kind='bar', title="open/opened/closed PRs")
    res.legend(loc='upper left', ncol=3, fontsize='small')
    plt.savefig('%s_opened_closed_PRs' % repository)

    pd_df_month = pd_df.loc[LAST_MONTH:]
    res = pd_df_month.plot(kind='bar', title="open/opened/closed PRs (last month)")
    res.legend(loc='upper left', ncol=3, fontsize='small')
    plt.savefig('%s_opened_closed_PRs_month' % repository)

    pd_df_total = pd_df.cumsum()
    res = pd_df_total.plot(kind='line', title="total open/opened/closed %s PRs" % repository)
    res.legend(loc='upper left', ncol=3, fontsize='small')
    plt.savefig('%s_opened_closed_PRs_cumulative' % repository)

    pd_df_total_year = pd_df_total.loc[LAST_YEAR:]
    res = pd_df_total_year.plot(kind='line', title="total open/opened/closed %s PRs (last year)" % repository)
    res.legend(loc='upper left', ncol=3, fontsize='small')
    plt.savefig('%s_opened_closed_PRs_cumulative_year' % repository)

    pd_df_total_month = pd_df_total.loc[LAST_MONTH:]
    res = pd_df_total_month.plot(kind='line', title="total open/opened/closed %s PRs (last month)" % repository)
    res.legend(loc='upper left', ncol=3, fontsize='small')
    plt.savefig('%s_opened_closed_PRs_cumulative_month' % repository)
Example #13
0
def plot_open_closed_PRs(created_ats, closed_ats, repository):
    """Plot open/closed PRs (in total) per day."""
    opened_closed = []
    days = []
    day = min(created_ats)
    while day <= datetime_parser("TODAY"):
        days.append(day)

        opened = sum([d.date() == day.date() for d in created_ats])
        closed = sum([d.date() == day.date() for d in closed_ats])
        open_cnt = opened - closed
        opened_closed.append((open_cnt, opened, closed))

        day += ONE_DAY

    pd_df = pd.DataFrame(opened_closed, days, columns=["open", "opened", "closed"]).sort()
    res = pd_df.plot(kind="bar", title="open/opened/closed PRs")
    res.legend(loc="upper left", ncol=3, fontsize="small")
    plt.savefig("%s_opened_closed_PRs" % repository)

    pd_df_month = pd_df.select(lambda d: d > LAST_MONTH)
    res = pd_df_month.plot(kind="bar", title="open/opened/closed PRs (last month)")
    res.legend(loc="upper left", ncol=3, fontsize="small")
    plt.savefig("%s_opened_closed_PRs_month" % repository)

    pd_df_total = pd_df.cumsum()
    res = pd_df_total.plot(kind="line", title="total open/opened/closed %s PRs" % repository)
    res.legend(loc="upper left", ncol=3, fontsize="small")
    plt.savefig("%s_opened_closed_PRs_cumulative" % repository)

    pd_df_total_year = pd_df_total.select(lambda d: d > LAST_YEAR)
    res = pd_df_total_year.plot(kind="line", title="total open/opened/closed %s PRs (last year)" % repository)
    res.legend(loc="upper left", ncol=3, fontsize="small")
    plt.savefig("%s_opened_closed_PRs_cumulative_year" % repository)

    pd_df_total_month = pd_df_total.select(lambda d: d > LAST_MONTH)
    res = pd_df_total_month.plot(kind="line", title="total open/opened/closed %s PRs (last month)" % repository)
    res.legend(loc="upper left", ncol=3, fontsize="small")
    plt.savefig("%s_opened_closed_PRs_cumulative_month" % repository)
Example #14
0
import easybuild.tools.build_log  # required to obtain an EasyBuild logger
from easybuild.tools.github import GITHUB_API_URL, fetch_github_token

from pr_overview import fetch_prs_data


GROUPS = [
    datetime.timedelta(7, 0, 0),  # 1 week
    datetime.timedelta(14, 0, 0),  # 2 weeks
    datetime.timedelta(30, 0, 0),  # ~1 month
    datetime.timedelta(60, 0, 0),  # ~2 months
    datetime.timedelta(180, 0, 0),  # ~6 months
]
ENDGROUP = datetime.timedelta(10 ** 6, 0, 0)  # very large
GROUP_LABELS = ["<1w", "1-2w", "2w-1m", "1-2m", "2-6m", ">6m"]
LAST_MONTH = datetime_parser("TODAY") - datetime.timedelta(30, 0, 0)
LAST_YEAR = datetime_parser("TODAY") - datetime.timedelta(365, 0, 0)
PICKLE_FILE = "%s_prs.dat"
ONE_DAY = datetime.timedelta(1, 0, 0)


def fetch_pr_data(pickle_file, github_user, github_account, repository):
    """Fetch PR data; either download or load from pickle file."""
    if pickle_file:
        print("Loading PR data from %s" % pickle_file)
        prs = cPickle.load(open(pickle_file, "r"))

    else:
        github_token = fetch_github_token(github_user)
        github = RestClient(GITHUB_API_URL, username=github_user, token=github_token, user_agent="eb-pr-stats")
        gh_repo = github.repos[github_account][repository]
Example #15
0
def gen_table_rows(prs):
    """Generate table rows."""
    col_tmpls = [
        "{v: %(number)s, f: '<a href=\"%(html_url)s\">#%(number)s</a>'}",
        "'%(user_login)s'",
        "'%(title)s'",
        "{v: %(age)s, f: '%(age)s days'}",
        "%(last_update)s",
        "%(unit_test)s",
        "%(style_check)s",
        "%(test_reports)s",
        "%(status)s",
        "%(signed_off)s",
        "%(participants)s",  # FIXME
        "0",  # FIXME
    ]
    row_tmpl = "            [" + ', '.join(col_tmpls) + "],"

    
    example_ut = [-1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    example_sc = [-1, -1, -1,  0,  0,  0,  1,  1,  1, -1, -1, -1,  0,  0,  0,  1,  1,  1, -1, -1, -1,  0,  0,  0,  1,  1,  1]
    example_tr = [-1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1, -1,  0,  1]
    example_statuses = [-3, -2, -1, -2, -1, 0, -1, 0, 1, -2, -1, 0, -1, 0, 1, 0, 1, 2, -1, 0, 1, 0, 1, 2, 1, 2, 3]

    merged_today = 0
    todays_date = date_parser('TODAY')

    last_update = datetime_parser(prs[0]['updated_at'].replace('T', ' ')[:-1])
    lines = ['        data.addRows([']
    for pr in prs:

        if pr['closed_at']:
            if date_parser(pr['closed_at'].split('T')[0]) == todays_date:
                merged_today += 1

        # only consider open PRs
        if pr['state'] != 'open':
            continue

        # shorten long titles, escape single quotes
        if len(pr['title']) > 30:
            pr['title'] = pr['title'][:30] + '...'
        pr['title'] = pr['title'].replace("'", "\\'")

        # determine status based on results of unit tests, style check and test reports
        unit_test = TEST_VALUES_MAP[pr['combined_status']]

        # initial value: '???' (unknown)
        style_check = 0
        test_reports = 0
        signed_off = False
        # iterate over all comments, last hit wins
        for comment in pr['issue_comments']['bodies']:
            if 'lgtm' in comment.lower() or 'style review ok' in comment.lower():
                style_check = 1

            if comment.lower().startswith('test report'):
                if 'SUCCESS' in comment:
                    test_reports = 1
                elif 'FAILED' in comment:
                    test_reports = -1

            if 'good to go' in comment.lower():
                signed_off = True

        status = unit_test + style_check + test_reports

        participants = len(nub(pr['issue_comments']['users']))

        year, month, day, hour, minutes, seconds = pr['updated_at'].replace('T', '@')[:-1].replace(':', '@').replace('-', '@').split('@')
        pr.update({
            'age': (datetime_parser('TODAY') - datetime_parser(pr['created_at'].split('T')[0])).days,
            'last_update': "new Date(%s, %s, %s, %s, %s, %s)" % (year, month, day, hour, minutes, seconds),
            'participants': participants,
            'signed_off': ['', 'true'][signed_off],
            'status': status,
            'style_check': TEST_RESULTS[style_check+1],
            'test_reports': TEST_RESULTS[test_reports+1],
            'unit_test': TEST_RESULTS[unit_test+1],
            'user_login': pr['user']['login'],
        })

        lines.append(row_tmpl % pr)

        last_update = max(datetime_parser(pr['updated_at'].replace('T', ' ')[:-1]), last_update)

    lines.append('        ]);')

    return len(lines)-2, '\n'.join(lines), merged_today, last_update
Example #16
0
def gen_table_rows(prs):
    """Generate table rows."""
    col_tmpls = [
        "{v: %(number)s, f: '<a href=\"%(html_url)s\">#%(number)s</a>'}",
        "'%(user_login)s'",
        "'%(title)s'",
        "{v: %(age)s, f: '%(age)s days'}",
        "%(last_update)s",
        "%(unit_test)s",
        "%(style_check)s",
        "%(test_reports)s",
        "%(status)s",
        "%(signed_off)s",
        "%(participants)s",  # FIXME
        "0",  # FIXME
    ]
    row_tmpl = "            [" + ', '.join(col_tmpls) + "],"

    merged_today = 0
    todays_date = date_parser('TODAY')

    last_update = datetime_parser(prs[0]['updated_at'].replace('T', ' ')[:-1])
    lines = ['        data.addRows([']
    for pr in prs:

        if pr['closed_at']:
            if date_parser(pr['closed_at'].split('T')[0]) == todays_date:
                merged_today += 1

        # only consider open PRs
        if pr['state'] != 'open':
            continue

        # shorten long titles, escape single quotes
        if len(pr['title']) > 30:
            pr['title'] = pr['title'][:30] + '...'
        pr['title'] = pr['title'].replace("'", "\\'")

        # determine status based on results of unit tests, style check and test reports
        unit_test = TEST_VALUES_MAP[pr['combined_status']]

        # initial value: '???' (unknown)
        style_check = 0
        test_reports = 0
        signed_off = False
        # iterate over all comments, last hit wins
        for comment in pr['issue_comments']['bodies']:
            if 'lgtm' in comment.lower() or 'style review ok' in comment.lower():
                style_check = 1

            if comment.lower().startswith('test report'):
                if 'SUCCESS' in comment:
                    test_reports = 1
                elif 'FAILED' in comment:
                    test_reports = -1

            if 'good to go' in comment.lower():
                signed_off = True

        status = unit_test + style_check + test_reports

        participants = len(nub(pr['issue_comments']['users']))

        raw_updated_at = pr['updated_at'].replace('T', '@')[:-1].replace(':', '@').replace('-', '@')
        year, month, day, hour, minutes, seconds = raw_updated_at.split('@')
        pr.update({
            'age': (datetime_parser('TODAY') - datetime_parser(pr['created_at'].split('T')[0])).days,
            'last_update': "new Date(%s, %s, %s, %s, %s, %s)" % (year, month, day, hour, minutes, seconds),
            'participants': participants,
            'signed_off': ['', 'true'][signed_off],
            'status': status,
            'style_check': TEST_RESULTS[style_check+1],
            'test_reports': TEST_RESULTS[test_reports+1],
            'unit_test': TEST_RESULTS[unit_test+1],
            'user_login': pr['user']['login'],
        })

        lines.append(row_tmpl % pr)

        last_update = max(datetime_parser(pr['updated_at'].replace('T', ' ')[:-1]), last_update)

    lines.append('        ]);')

    return len(lines)-2, '\n'.join(lines), merged_today, last_update
Example #17
0
from easybuild.tools.utilities import nub

from vsc.utils.dateandtime import date_parser, datetime_parser

log = fancylogger.getLogger()

GROUPS = [
    datetime.timedelta(7, 0, 0),  # 1 week
    datetime.timedelta(14, 0, 0),  # 2 weeks
    datetime.timedelta(30, 0, 0),  # ~1 month
    datetime.timedelta(60, 0, 0),  # ~2 months
    datetime.timedelta(180, 0, 0),  # ~6 months
]
ENDGROUP = datetime.timedelta(10**6, 0, 0)  # very large
GROUP_LABELS = ['<1w', '1-2w', '2w-1m', '1-2m', '2-6m', '>6m']
LAST_MONTH = datetime_parser('TODAY') - datetime.timedelta(30, 0, 0)
LAST_YEAR = datetime_parser('TODAY') - datetime.timedelta(365, 0, 0)
PICKLE_FILE = '%s_prs.dat'
ONE_DAY = datetime.timedelta(1, 0, 0)

HTML_FILE = '%s_pr_overview.html'
HTML_HEADER = """
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["table"]});
      google.setOnLoadCallback(drawTable);
      function drawTable() {
        var data = new google.visualization.DataTable();
"""