diff --git a/HOW_TO_RELEASE.md b/HOW_TO_RELEASE.md index 9d1164547b9..28f7b8e8775 100644 --- a/HOW_TO_RELEASE.md +++ b/HOW_TO_RELEASE.md @@ -23,14 +23,13 @@ upstream https://github.com/pydata/xarray (push) ```sh git fetch upstream --tags ``` - This will return a list of all the contributors since the last release: + Then run ```sh - git log "$(git tag --sort=v:refname | tail -1).." --format=%aN | sort -u | perl -pe 's/\n/$1, /' - ``` - This will return the total number of contributors: - ```sh - git log "$(git tag --sort=v:refname | tail -1).." --format=%aN | sort -u | wc -l + python ci/release_contributors.py ``` + (needs `gitpython` and `toolz` / `cytoolz`) + + and copy the output. 3. Write a release summary: ~50 words describing the high level features. This will be used in the release emails, tweets, GitHub release notes, etc. 4. Look over whats-new.rst and the docs. Make sure "What's New" is complete diff --git a/ci/release_contributors.py b/ci/release_contributors.py new file mode 100644 index 00000000000..dab95c651c5 --- /dev/null +++ b/ci/release_contributors.py @@ -0,0 +1,49 @@ +import re +import textwrap + +import git +from tlz.itertoolz import last, unique + +co_author_re = re.compile(r"Co-authored-by: (?P[^<]+?) <(?P.+)>") + + +def main(): + repo = git.Repo(".") + + most_recent_release = last(repo.tags) + + # extract information from commits + contributors = {} + for commit in repo.iter_commits(f"{most_recent_release.name}.."): + matches = co_author_re.findall(commit.message) + if matches: + contributors.update({email: name for name, email in matches}) + contributors[commit.author.email] = commit.author.name + + # deduplicate and ignore + # TODO: extract ignores from .github/release.yml + ignored = ["dependabot", "pre-commit-ci"] + unique_contributors = unique( + contributor + for contributor in contributors.values() + if contributor.removesuffix("[bot]") not in ignored + ) + + sorted_ = sorted(unique_contributors) + if len(sorted_) > 1: + names = f"{', '.join(sorted_[:-1])} and {sorted_[-1]}" + else: + names = "".join(sorted_) + + statement = textwrap.dedent( + f"""\ + Thanks to the {len(sorted_)} contributors to this release: + {names} + """.rstrip() + ) + + print(statement) + + +if __name__ == "__main__": + main()