diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000000..951678f514 --- /dev/null +++ b/.mailmap @@ -0,0 +1,55 @@ +# See https://github.com/git/git/blob/master/Documentation/mailmap.txt +adil +adil +aG0aep6G +Alex Rønne Petersen +amaury +Anders Ronnbrant +Andrej Mitrovic +Andrey Zherikov +biotronic +Brian Schott +Christian Juelg +Clement Courbet +Daniel Murphy +Dave Gallets +David +Denis Shelomovskij +Ed McCardell +Hara Kenji +Iain Buclaw +Iain Buclaw ibuclaw +Ilya Yaroshenko +Jacob Carlborg +Jakob Øvrum +Jakob Øvrum +John Colvin +Jonathan M Davis +Jordi Sayol +Kai Nacke +kinke +Mark Barbone <30397247+mb64@users.noreply.github.com> +Mark Barbone <30397247+mb64@users.noreply.github.com> Mark Barbone <> +Martin Nowak +Mathias Lang +Mathias Lang +Mathias Lang +monarchdodra +Petar Kirov +ponce +Rainer Schuetze +Razvan Nitu +Robert burner Schadek +Robert burner Schadek +Safety0ff +Safety0ff +shoo +Stefan Koch +Stefan Rohe +Timothee Cour +Torarin +Ulrich Küttler +Walter Waldron +Yazan Dabain +Михаил Страшун +Yao Gómez diff --git a/contributors.d b/contributors.d new file mode 100755 index 0000000000..f99535adf6 --- /dev/null +++ b/contributors.d @@ -0,0 +1,148 @@ +#!/usr/bin/env rdmd + +/** +Query contributors between two D releases. + +Copyright: D Language Foundation 2017. + +License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). + +Example usage: + +--- +./contributors.d "v2.074.0..v2.075.0" +--- + +Author: Sebastian Wilzbach +*/ + +import std.array; +import std.algorithm; +import std.conv; +import std.exception; +import std.file; +import std.format; +import std.process; +import std.path; +import std.range; +import std.stdio; +import std.string; +import std.typecons; + +/// Name +struct GitAuthor +{ + string name, email; + string toString() + { + return "%s <%s>".format(name, email); + } +} + +/// Options for finding authors +struct FindConfig +{ + bool refreshTags; /// will query github.com for new tags + bool noMerges; // will ignore merge commits + bool showAllContributrs; // will ignore the revRange and show all contributors + string cwd; // working directory (should be tools) + string mailmapFile; // location to the .mailmap file +} + +/** +Search all git commit messages within revRange of all D repositories +Returns: Array that maps each git `Author: ...` line to a GitAuthor +*/ +auto findAuthors(string revRange, FindConfig config) +{ + Appender!(GitAuthor[]) authors; + int commits; + foreach (repo; ["dmd", "druntime", "phobos", "dlang.org", "tools", "installer"] + .map!(r => buildPath(config.cwd, "..", r))) + { + if (config.refreshTags) + { + auto cmd = ["git", "-C", repo, "fetch", "--tags", "https://github.com/dlang/" ~ repo.baseName, + "+refs/heads/*:refs/remotes/upstream/*"]; + auto p = pipeProcess(cmd, Redirect.stdout); + enforce(wait(p.pid) == 0, "Failed to execute '%(%s %)'.".format(cmd)); + } + + auto cmd = ["git", "-c", "mailmap.file=%s".format(config.mailmapFile), "-C", repo, "log", "--use-mailmap", "--pretty=format:%aN|%aE"]; + if (!config.showAllContributrs) + cmd ~= revRange; + if (config.noMerges) + cmd ~= "--no-merges"; + + auto p = pipeProcess(cmd, Redirect.stdout); + scope(exit) enforce(wait(p.pid) == 0, "Failed to execute '%(%s %)'.".format(cmd)); + + authors ~= p.stdout + .byLineCopy + .tee!(_ => commits++) + .map!((line){ + auto ps = line.splitter("|"); + return GitAuthor(ps.front, ps.dropOne.front); + }) + .filter!(a => a.name != "The Dlang Bot"); + } + if (!config.showAllContributrs) + stderr.writefln("Looked at %d commits in %s", commits, revRange); + else + stderr.writefln("Looked at %d commits", commits); + return authors.data; +} + +/// Sorts the authors and filters for duplicates +auto reduceAuthors(GitAuthors)(GitAuthors authors) +{ + import std.uni : sicmp; + return authors + .sort!((a, b) => sicmp(a.name, b.name) < 0) + .uniq!((a, b) => a.name == b.name); +} + +int main(string[] args) +{ + import std.getopt; + string revRange; + FindConfig config = { + cwd: __FILE_FULL_PATH__.dirName.asNormalizedPath.to!string, + }; + config.mailmapFile = config.cwd.buildPath(".mailmap"); + + enum PrintMode { name, markdown, ddoc, csv, git} + PrintMode printMode; + + auto helpInformation = getopt( + args, + std.getopt.config.passThrough, + "f|format", "Result format (name, markdown, ddoc, csv, git)", &printMode, + "a|all", "Show all contributors", &config.showAllContributrs, + "refresh-tags", "Refresh tags", &config.refreshTags, + "no-merges", "Ignore merge commits", &config.noMerges, + ); + + if (helpInformation.helpWanted || (args.length < 2 && !config.showAllContributrs)) + { +`D contributors extractor. +./contributors.d "v2.075.0..v2.076.0"`.defaultGetoptPrinter(helpInformation.options); + return 1; + } + + revRange = args.length > 1 ? args[1] : null; + revRange.findAuthors(config) + .reduceAuthors + .each!((a){ + with(PrintMode) + final switch (printMode) + { + case name: a.name.writeln; break; + case markdown: writefln("- %s", a.name); break; + case ddoc: writefln("$(D_CONTRIBUTOR %s)", a.name); break; + case csv: writefln("%s, %s", a.name, a.email); break; + case git: writefln("%s <%s>", a.name, a.email); break; + } + }); + return 0; +} diff --git a/posix.mak b/posix.mak index 906880819d..33836cb289 100644 --- a/posix.mak +++ b/posix.mak @@ -42,6 +42,7 @@ DUBFLAGS = --arch=$(subst 32,x86,$(subst 64,x86_64,$(MODEL))) TOOLS = \ $(ROOT)/catdoc \ $(ROOT)/checkwhitespace \ + $(ROOT)/contributors \ $(ROOT)/ddemangle \ $(ROOT)/detab \ $(ROOT)/rdmd \