mirror of
https://github.com/dlang/tools.git
synced 2025-04-25 12:40:21 +03:00
159 lines
4.8 KiB
D
Executable file
159 lines
4.8 KiB
D
Executable file
#!/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 <my@email.com>
|
|
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 showAllContributors; // 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;
|
|
auto repos = ["dmd", "phobos", "dlang.org", "tools", "installer"];
|
|
if (config.showAllContributors)
|
|
repos ~= ["dub", "dub-registry", "dconf.org"];
|
|
|
|
foreach (repo; repos.map!(r => buildPath(config.cwd, "..", r)))
|
|
{
|
|
if (!repo.exists)
|
|
{
|
|
stderr.writefln("Warning: %s doesn't exist. " ~
|
|
"Consider running: git clone https://github.com/dlang/%s ../%2$s",
|
|
repo, repo.baseName);
|
|
continue;
|
|
}
|
|
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.showAllContributors)
|
|
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.showAllContributors)
|
|
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);
|
|
}
|
|
|
|
version(Contributors_Lib) {} else
|
|
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.showAllContributors,
|
|
"refresh-tags", "Refresh tags", &config.refreshTags,
|
|
"no-merges", "Ignore merge commits", &config.noMerges,
|
|
);
|
|
|
|
if (helpInformation.helpWanted || (args.length < 2 && !config.showAllContributors))
|
|
{
|
|
`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;
|
|
}
|