Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to order results by last commit date #37

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions org_status/encoders/gitman.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ def convert_repo_list_to_format(self, repos):
name = parse(repo.web_url).repo
yml_data['sources'].append({'name': name,
'repo': repo.web_url,
'rev': 'master'})

'rev': 'master',
})
return yaml.dump(yml_data, default_flow_style=False)
3 changes: 2 additions & 1 deletion org_status/org_hosts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ def repositories(self):

class RepoStatus:

def __init__(self, repo_url, repo_status):
def __init__(self, repo_url, repo_status, last_commit_date):
self.repo_url = repo_url
self.repo_status = repo_status
self.last_commit_date = last_commit_date


def get_all_supported_hosts():
Expand Down
12 changes: 11 additions & 1 deletion org_status/org_hosts/github.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
from types import MethodType

import requests
from IGitt.GitHub.GitHub import GitHubToken
Expand All @@ -21,6 +22,9 @@ def __init__(self, token, group, **kargs):
self._token = GitHubToken(token)
self._org = GitHubOrganization(self._token, self._group)

for repo in self._org.repositories:
repo.get_last_commit_date = MethodType(_get_last_commit_date, repo)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like how you are patching in a method here. We already have support for Gitman and once your #34 gets merged we will support --use-repo-list. This method will work when the merge happens.

At this point of time, we have two ways to address this problem.

  • Provide a static method on OrgHost to get the commit dates of a given repo independently.
  • We already support tools like Gitman, we can use them to clone the repos and get commit dates from the local copy.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jayvdb Your thoughts?


self._status_provider = []
for i in enumerate(self.StatusProvider):
self._status_provider.append(self.StatusProvider[i[0]](self._group))
Expand Down Expand Up @@ -56,8 +60,14 @@ def process_repository(self, repo, branch='master'):
elif Status.ERROR in repo_status:
repo_status = Status.ERROR

return RepoStatus(repo.web_url, repo_status)
last_commit_date = repo.get_last_commit_date()

return RepoStatus(repo.web_url, repo_status, last_commit_date)

@property
def repositories(self):
return self._org.repositories


def _get_last_commit_date(self):
return self.data._data['pushed_at']
17 changes: 16 additions & 1 deletion org_status/org_hosts/gitlab.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
from types import MethodType

import requests
from IGitt.GitLab.GitLab import GitLabPrivateToken
Expand All @@ -22,6 +23,9 @@ def __init__(self, token, group, **kargs):
self._token = GitLabPrivateToken(token)
self._org = GitLabOrganization(self._token, self._group)

for repo in self._org.repositories:
repo.get_last_commit_date = MethodType(_get_last_commit_date, repo)

self._status_provider = self.StatusProvider(self._group)

@classmethod
Expand All @@ -39,8 +43,19 @@ def process_repository(self, repo, branch='master'):
self.HostName,
branch=branch)

return RepoStatus(repo.web_url, repo_status)
last_commit_date = repo.get_last_commit_date()

return RepoStatus(repo.web_url, repo_status, last_commit_date)

@property
def repositories(self):
return self._org.repositories


def _get_last_commit_date(self):
repo_commit_dates = ['']
for commit in self.commits:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this will not work with --use-repo-list mode from #34, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why iterate over every commit?

That is horribly inefficient.

Any list of commits should be already pre-sorted, most recent first, so you should be able to get only the first using next(iter(commit_list))

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a problem in the GitLabRepository implementation, that needs to be solved upstream in IGitt.

If so, add a comment here in this PR explaining the problem, and we'll check and you can create an issue and solve the IGitt bug.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the list of commits is not pre-sorted.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, we'll get IGitt fixed so this doesnt need to be so ugly.

repo_commit_dates.append(commit.data._data['committed_date'])
repo_commit_dates.sort()

return repo_commit_dates[-1]
17 changes: 13 additions & 4 deletions org_status/org_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ def aggregate_org_status(org_host, threads=2):
return pool.map(org_host.process_repository, org_host.repositories)


def present_status(statuses, no_color):
def present_status(statuses, no_color, sort):
color = (lambda l, *_: l) if no_color else colored
r_pass, r_fail, r_unknown, r_error = 0, 0, 0, 0

if sort:
statuses.sort(key=lambda status: status.last_commit_date, reverse=True)

for status in statuses:
repo_status = status.repo_status or Status.UNDETERMINED
status_text = repo_status.value
Expand All @@ -68,8 +71,13 @@ def present_status(statuses, no_color):
r_unknown += 1
continue

print('{repo}: {status}'.format(
repo=status.repo_url, status=status_text))
date_text = color(status.last_commit_date, 'blue')

print('{repo}: {status} (last commit: {date})'.format(
repo=status.repo_url,
status=status_text,
date=date_text,
))

print('{} Passing, {} Failing, {} Error, {} Unknown '
'of {} Repositories'.format(
Expand All @@ -85,6 +93,7 @@ def get_argument_parser():
parser.add_argument('--hosts-only', '-o', action='store_true')
parser.add_argument('--skip-host-checks', action='store_true')
parser.add_argument('--export-repos', type=str)
parser.add_argument('--sort-by-last-commit', action='store_true')
parser.add_argument('--format', type=str, default='gitman')
parser.add_argument('--check-providers-only', action='store_true')

Expand Down Expand Up @@ -196,7 +205,7 @@ def main():
continue

org_status = aggregate_org_status(org_host, threads=args.threads)
present_status(org_status, args.no_color)
present_status(org_status, args.no_color, args.sort_by_last_commit)

if args.export_repos:
export_data = encode_repo_list(all_repositories, args.format, styled)
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ git+https://gitlab.com/gitmate/open-source/IGitt.git#egg=IGitt
requests
termcolor
giturlparse
pyyaml
gitman
4 changes: 4 additions & 0 deletions tests/fixtures/present_status_output_no_sort.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
https://github.com/foo/r0: passing (last commit: 2018-11-05T08:20:37Z)
https://github.com/foo/r1: passing (last commit: 2018-11-02T17:31:46Z)
https://github.com/foo/r2: passing (last commit: 2018-11-06T02:27:42Z)
0 Passing, 0 Failing, 0 Error, 0 Unknown of 3 Repositories
4 changes: 4 additions & 0 deletions tests/fixtures/present_status_output_sorted.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
https://github.com/foo/r2: passing (last commit: 2018-11-06T02:27:42Z)
https://github.com/foo/r0: passing (last commit: 2018-11-05T08:20:37Z)
https://github.com/foo/r1: passing (last commit: 2018-11-02T17:31:46Z)
0 Passing, 0 Failing, 0 Error, 0 Unknown of 3 Repositories
40 changes: 39 additions & 1 deletion tests/test_main.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import pytest
from unittest import mock
from io import StringIO

from argparse import ArgumentParser

from org_status.org_status import (get_argument_parser,
generate_fetch_jobs,
get_host_token,
get_supported_status_providers,
get_status_provider_statuses)
get_status_provider_statuses,
present_status,
)
from org_status.org_hosts import get_all_supported_hosts


Expand Down Expand Up @@ -56,3 +59,38 @@ def test_get_status_provider_statuses():
expected_status_provider_statuses.add((status_provider, status))

assert actual_status_provider_statuses == expected_status_provider_statuses


class MockRepoStatus():
def __init__(self, value):
self.value = value


class MockStatus():
def __init__(self, repo_url, repo_status, last_commit_date):
self.repo_url = repo_url
self.repo_status = MockRepoStatus(repo_status)
self.last_commit_date = last_commit_date


def test_present_status():
statuses = [MockStatus('https://github.com/foo/r0',
'passing', '2018-11-05T08:20:37Z'),
MockStatus('https://github.com/foo/r1',
'passing', '2018-11-02T17:31:46Z'),
MockStatus('https://github.com/foo/r2',
'passing', '2018-11-06T02:27:42Z')]

with mock.patch('sys.stdout', new=StringIO()) as output:
present_status(statuses, True, False)
actual = output.getvalue().strip()
with open('tests/fixtures/present_status_output_no_sort.txt', 'r') as f:
expected = f.read()
assert actual == expected

with mock.patch('sys.stdout', new=StringIO()) as output:
present_status(statuses, True, True)
actual = output.getvalue().strip()
with open('tests/fixtures/present_status_output_sorted.txt', 'r') as f:
expected = f.read()
assert actual == expected