Completed
Push — master ( 291ee9...9d841e )
by Matěj
20s queued 12s
created

ssg._contributors   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 125
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 81
dl 0
loc 125
rs 10
c 0
b 0
f 0
wmc 12

5 Functions

Rating   Name   Duplication   Size   Complexity  
A generate() 0 21 2
A _get_contributor_email_mapping() 0 8 2
A _names_sorted_by_last_name() 0 2 3
A _get_name_used_most_in_contributions() 0 3 1
A _get_contributions_by_canonical_email() 0 16 4
1
import collections
0 ignored issues
show
Coding Style introduced by
This module should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
2
import datetime
3
import re
4
import subprocess
0 ignored issues
show
Unused Code introduced by
The import subprocess seems to be unused.
Loading history...
5
import os.path
6
7
from ssg._shims import subprocess_check_output
8
9
10
MANUAL_EDIT_WARNING = """This file is generated using the %s script. DO NOT MANUALLY EDIT!!!!
11
Last Modified: %s
12
""" % (os.path.basename(__file__), datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
13
14
email_mappings = {
0 ignored issues
show
Coding Style Naming introduced by
The name email_mappings does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
15
    # Dave / David Smith
16
    "[email protected]": "[email protected]",
17
    "[email protected]": "[email protected]",
18
    # Firas AlShafei
19
    "[email protected]": "[email protected]",
20
    # Frank Caviggia
21
    "[email protected]": "[email protected]",
22
    # Greg Elin
23
    "[email protected]": "[email protected]",
24
    # Jean-Baptiste Donnette
25
    "[email protected]": "[email protected]",
26
    # Marek Haicman
27
    "[email protected]": "[email protected]",
28
    # Martin Preisler
29
    "[email protected]": "[email protected]",
30
    # Nathan Peters
31
    "[email protected]": "[email protected]",
32
    "[email protected]": "[email protected]",
33
    # Philippe Thierry
34
    "[email protected]": "[email protected]",
35
    "[email protected]": "[email protected]",
36
    "[email protected]": "[email protected]",
37
    # Robin Price II
38
    "[email protected]": "[email protected]",
39
    "[email protected]": "[email protected]",
40
    # Zbynek Moravec
41
    "[email protected]": "[email protected]",
42
    "[email protected]": "[email protected]",
43
    # Jeff Blank
44
    "[email protected]": "[email protected]",
45
    # Shawn Wells
46
    "[email protected]": "[email protected]",
47
    "[email protected]": "[email protected]",
48
    # Simon Lukasik
49
    "[email protected]": "[email protected]",
50
    # Andrew Gilmore
51
    "[email protected]": "[email protected]",
52
53
    # No idea / ignore
54
    "lyd@chippy.(none)": "",
55
    "[email protected]": "",
56
    "[email protected]": "",
57
    "root@rhel6.(none)": "",
58
}
59
60
name_mappings = {
0 ignored issues
show
Coding Style Naming introduced by
The name name_mappings does not conform to the constant naming conventions ((([A-Z_][A-Z0-9_]*)|(__.*__))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
61
    "Gabe": "Gabe Alford",
62
    "Olivier": "Olivier Bonhomme",
63
    "OnceUponALoop": "Firas AlShafei",
64
}
65
66
67
def _get_contributions_by_canonical_email(output):
68
    contributions_by_email = collections.defaultdict(list)
69
    for line in output.split("\n"):
70
        match = re.match(r"[\s]*([0-9]+)\s+(.+)\s+\<(.+)\>", line)
71
        if match is None:
72
            continue
73
74
        commits_count, author_name, email = match.groups()
75
76
        canonical_email = email_mappings.get(email, email)
77
78
        if canonical_email == "":
79
            continue  # ignored
80
81
        contributions_by_email[canonical_email].append((int(commits_count), author_name))
82
    return contributions_by_email
83
84
85
def _get_name_used_most_in_contributions(contribution_sets):
86
    _, name_used_most = sorted(contribution_sets, reverse=True)[0]
87
    return name_used_most
88
89
90
def _get_contributor_email_mapping(contributions_by_email):
91
    contributors = {}
92
    for email in contributions_by_email:
93
        name_used_most = _get_name_used_most_in_contributions(contributions_by_email[email])
94
        canonical_name_used_most = name_mappings.get(name_used_most, name_used_most)
95
96
        contributors[canonical_name_used_most] = email
97
    return contributors
98
99
100
def _names_sorted_by_last_name(names):
101
    return sorted(names, key=lambda x: tuple(n.upper() for n in x.split(" "))[::-1])
102
103
104
def generate():
0 ignored issues
show
Coding Style introduced by
This function should have a docstring.

The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:

class SomeClass:
    def some_method(self):
        """Do x and return foo."""

If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.

Loading history...
105
    output = subprocess_check_output(["git", "shortlog", "-se"]).decode("utf-8")
106
    contributions_by_email = _get_contributions_by_canonical_email(output)
107
    contributors = _get_contributor_email_mapping(contributions_by_email)
108
109
    contributors_md = "<!---%s--->\n\n" % MANUAL_EDIT_WARNING
110
    contributors_md += \
111
        "The following people have contributed to the SCAP Security Guide project\n"
112
    contributors_md += "(listed in alphabetical order):\n\n"
113
114
    contributors_xml = "<!--%s-->\n\n" % MANUAL_EDIT_WARNING
115
    contributors_xml += "<text>\n"
116
117
    for name in _names_sorted_by_last_name(list(contributors.keys())):
118
        email = contributors[name]
119
        contributors_md += "* %s <%s>\n" % (name, email)
120
        contributors_xml += "<contributor>%s &lt;%s&gt;</contributor>\n" % (name, email)
121
122
    contributors_xml += "</text>\n"
123
124
    return contributors_md, contributors_xml
125