1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""Utility script to work with the CITATION.cff file"""
import logging
import subprocess
from pathlib import Path
import click
from ruamel.yaml import YAML
log = logging.getLogger(__name__)
EXCLUDE_AUTHORS = ["azure-pipelines[bot]", "GitHub Actions"]
GAMMAPY_CC = [
"Axel Donath",
"Bruno Khelifi",
"Catherine Boisson",
"Christopher van Eldik",
"David Berge",
"Fabio Acero",
"Fabio Pintore",
"James Hinton",
"José Luis Contreras Gonzalez",
"Matthias Fuessling",
"Régis Terrier",
"Roberta Zanin",
"Rubén López-Coto",
"Stefan Funk",
]
# Approved authors that requested to be added to CITATION.cff
ADDITIONAL_AUTHORS = [
"Amanda Weinstein",
"Tim Unbehaun",
]
PATH = Path(__file__).parent.parent
LAST_LTS = "v1.0"
NOW = "HEAD"
@click.group()
def cli():
pass
def get_git_shortlog_authors(since_last_lts=False):
"""Get list of authors from git shortlog"""
authors = []
command = ("git", "shortlog", "--summary", "--numbered")
if since_last_lts:
command += (f"{LAST_LTS}..{NOW}",)
result = subprocess.check_output(command, stderr=subprocess.STDOUT).decode()
data = result.split("\n")
for row in data:
parts = row.split("\t")
if len(parts) == 2:
n_commits, author = parts
if author not in EXCLUDE_AUTHORS:
authors.append(author)
return authors
def get_full_name(author_data):
"""Get full name from CITATION.cff parts"""
parts = []
parts.append(author_data["given-names"])
name_particle = author_data.get("name-particle", None)
if name_particle:
parts.append(name_particle)
parts.append(author_data["family-names"])
return " ".join(parts)
def get_citation_cff_authors():
"""Get list of authors from CITATION.cff"""
authors = []
citation_file = PATH / "CITATION.cff"
yaml = YAML()
with citation_file.open("r") as stream:
data = yaml.load(stream)
for author_data in data["authors"]:
full_name = get_full_name(author_data)
authors.append(full_name)
return authors
@cli.command("sort", help="Sort authors by commits")
def sort_citation_cff():
"""Sort CITATION.cff according to the git shortlog"""
authors = get_git_shortlog_authors()
citation_file = PATH / "CITATION.cff"
yaml = YAML()
yaml.preserve_quotes = True
with citation_file.open("r") as stream:
data = yaml.load(stream)
authors_cff = get_citation_cff_authors()
sorted_authors = []
for author in authors:
idx = authors_cff.index(author)
sorted_authors.append(data["authors"][idx])
data["authors"] = sorted_authors
with citation_file.open("w") as stream:
yaml.dump(data, stream=stream)
@cli.command("check", help="Check git shortlog vs CITATION.cff authors")
@click.option("--since-last-lts", is_flag=True, help="Show authors since last LTS")
def check_author_lists(since_last_lts):
"""Check CITATION.cff with git shortlog"""
authors = set(get_git_shortlog_authors(since_last_lts))
authors_cff = set(get_citation_cff_authors())
message = "****Authors not in CITATION.cff****\n\n "
diff = authors.difference(authors_cff)
print(message + "\n ".join(sorted(diff)) + "\n")
message = "****Authors not in shortlog****\n\n "
diff = authors_cff.difference(authors)
authors_annotated = []
for author in sorted(diff):
if author in ADDITIONAL_AUTHORS:
author = "(AA) " + author
elif author in GAMMAPY_CC:
author = "(CC) " + author
else:
author = 5 * " " + author
authors_annotated.append(author)
print(message + "\n ".join(authors_annotated) + "\n")
print("(CC) = Coordination Committee, (AA) = Additional Authors, (OO) = Opted out\n")
if __name__ == "__main__":
cli()
|