feat(freeze): no authors in the config, no author check
A repository that takes commits from people it cannot list has no way to freeze a range today: a null `authors` falls back to `git config user.email`, so every foreign author or committer fails. Null, or no key, now means neither is checked; the freeze warns that it did not check them and records `authors` as null. A list is checked as before. An empty list, which no commit could pass, is a config error that points at null. Released as 1.1.0.
This commit is contained in:
parent
0d3d8ed2d2
commit
c6b4d78245
10 changed files with 52 additions and 49 deletions
|
|
@ -211,20 +211,18 @@ namespace Crafter::Review::Freeze {
|
|||
fail(std::format("{} is not the toplevel of a git checkout", repo));
|
||||
return report;
|
||||
}
|
||||
std::vector<std::string> authors = options.authors;
|
||||
if (authors.empty()) authors = Config::Authors({{"authors", nullptr}}, repo);
|
||||
if (authors.empty()) {
|
||||
fail("no author identity: set `authors` in .review-gates/config.json or git config user.email");
|
||||
return report;
|
||||
}
|
||||
const std::optional<std::vector<std::string>>& authors = options.authors;
|
||||
const Base base = ResolveBase(repo, options.base, options.configBase, options.rangeFrom);
|
||||
if (!base.failure.empty()) {
|
||||
fail(base.failure);
|
||||
return report;
|
||||
}
|
||||
const std::string head = Artifact::TreeHead(repo);
|
||||
Json authorList = Json::array();
|
||||
for (const std::string& author : authors) authorList.push_back(author);
|
||||
Json authorList;
|
||||
if (authors) {
|
||||
authorList = Json::array();
|
||||
for (const std::string& author : *authors) authorList.push_back(author);
|
||||
}
|
||||
report["base"] = base.sha;
|
||||
report["baseFrom"] = base.how;
|
||||
report["upstream"] = base.upstream ? Json(*base.upstream) : Json();
|
||||
|
|
@ -261,11 +259,12 @@ namespace Crafter::Review::Freeze {
|
|||
commitList.push_back({{"sha", c.sha}, {"subject", c.subject}, {"author", c.author}, {"committer", c.committer}, {"sig", c.sig}});
|
||||
}
|
||||
report["commits"] = commitList;
|
||||
const std::string authorText = Dyn::Join(authors, ", ");
|
||||
if (!authors) warn("no authors in .review-gates/config.json: author and committer not checked");
|
||||
const std::string authorText = authors ? Dyn::Join(*authors, ", ") : std::string();
|
||||
for (const Commit& c : commits) {
|
||||
const std::string who = std::format("{} {}", Head12(c.sha), Dyn::Repr(Dyn::Slice(c.subject, 0, 50)));
|
||||
if (!std::ranges::contains(authors, c.author)) fail(std::format("{}: author {} not in {}", who, c.author, authorText));
|
||||
if (!std::ranges::contains(authors, c.committer)) fail(std::format("{}: committer {} not in {}", who, c.committer, authorText));
|
||||
if (authors && !std::ranges::contains(*authors, c.author)) fail(std::format("{}: author {} not in {}", who, c.author, authorText));
|
||||
if (authors && !std::ranges::contains(*authors, c.committer)) fail(std::format("{}: committer {} not in {}", who, c.committer, authorText));
|
||||
if (const std::optional<std::string> trailer = AiTrailer(c.body)) {
|
||||
const bool forbid = options.aiTrailers == "forbid";
|
||||
const std::string message = std::format("{}: AI attribution trailer {}{}", who, Dyn::Repr(Dyn::Strip(*trailer)),
|
||||
|
|
@ -472,7 +471,7 @@ namespace Crafter::Review::Freeze {
|
|||
options.replace = arguments.replace;
|
||||
options.worktree = arguments.worktree;
|
||||
options.requireSigned = arguments.requireSigned || Dyn::Truthy(Dyn::Get(config, "requireSigned"));
|
||||
options.authors = Config::Authors(config, repo);
|
||||
options.authors = Config::Authors(config);
|
||||
options.aiTrailers = Dyn::Str(Dyn::Get(config, "aiTrailers"));
|
||||
options.allowDirty = allowDirty;
|
||||
const Json& configBase = Dyn::Get(config, "base");
|
||||
|
|
|
|||
Loading…
Reference in a new issue