Files
retoor 3c4334cec9 feat: implement MoloApp plans 01-15 with integration
Full C++23 framework tree: runtime, observability, security,
data, app, realtime, supervisor, clients, CLI, example plus
enterprise tenancy, audit, operability, governance,
supplychain. Postgres via docker compose for tests.
2026-10-23 18:20:04 +02:00

144 lines
4.1 KiB
C++

#include "Workflow.hpp"
#include <cstdio>
#include "Caps.hpp"
namespace molo::example::fw {
bool parse_commit(const std::string& subject, const std::string& body,
CommitInfo& out, std::string& error) {
std::string s = subject;
if (s.size() > (std::size_t)caps::kMaxCommitSubject) {
error = "subject too long";
return false;
}
std::size_t colon = s.find(':');
if (colon == std::string::npos) {
error = "missing colon";
return false;
}
std::string head = s.substr(0, colon);
out.description = s.substr(colon + 1);
while (!out.description.empty() && out.description.front() == ' ')
out.description.erase(out.description.begin());
if (!head.empty() && head.back() == '!') {
out.breaking = true;
head.pop_back();
}
std::size_t paren = head.find('(');
if (paren == std::string::npos) {
out.type = head;
} else {
out.type = head.substr(0, paren);
std::size_t close = head.find(')', paren);
if (close == std::string::npos) {
error = "unclosed scope";
return false;
}
out.scope = head.substr(paren + 1, close - paren - 1);
}
const char* allowed[] = {"feat", "fix", "docs", "style", "refactor",
"perf", "test", "build", "ci", "chore"};
bool ok = false;
for (const char* t : allowed) {
if (out.type == t) {
ok = true;
break;
}
}
if (!ok) {
error = "unknown type: " + out.type;
return false;
}
if (body.find("BREAKING CHANGE") != std::string::npos) out.breaking = true;
return true;
}
std::string bump_name(Bump bump) {
switch (bump) {
case Bump::None: return "none";
case Bump::Patch: return "patch";
case Bump::Minor: return "minor";
case Bump::Major: return "major";
}
return "none";
}
Bump ReleasePlanner::decide(const std::vector<CommitInfo>& commits) const {
bool feat = false, fix = false;
for (const auto& c : commits) {
if (c.breaking) return Bump::Major;
if (c.type == "feat") feat = true;
if (c.type == "fix") fix = true;
}
if (feat) return Bump::Minor;
if (fix) return Bump::Patch;
return Bump::None;
}
std::string ReleasePlanner::next_version(
const std::string& current,
const std::vector<CommitInfo>& commits) const {
int major = 0, minor = 0, patch = 0;
std::sscanf(current.c_str(), "%d.%d.%d", &major, &minor, &patch);
switch (decide(commits)) {
case Bump::Major: return std::to_string(major + 1) + ".0.0";
case Bump::Minor:
return std::to_string(major) + "." + std::to_string(minor + 1) + ".0";
case Bump::Patch:
return std::to_string(major) + "." + std::to_string(minor) + "." +
std::to_string(patch + 1);
case Bump::None: return current;
}
return current;
}
std::string ChangelogWriter::entry(
const std::string& version, const std::string& date,
const std::vector<CommitInfo>& commits) const {
std::string added, changed, fixed, removed;
for (const auto& c : commits) {
std::string line =
"- " + (c.scope.empty() ? "" : "(" + c.scope + ") ") + c.description +
"\n";
if (c.breaking)
changed += line;
else if (c.type == "feat")
added += line;
else if (c.type == "fix")
fixed += line;
else
changed += line;
}
std::string out = "## [" + version + "] - " + date + "\n";
if (!added.empty()) out += "### Added\n" + added;
if (!changed.empty()) out += "### Changed\n" + changed;
if (!fixed.empty()) out += "### Fixed\n" + fixed;
if (!removed.empty()) out += "### Removed\n" + removed;
int lines = 0;
for (char c : out) {
if (c == '\n') ++lines;
}
if (lines > caps::kMaxChangelogLines)
out += "(truncated to cap)\n";
return out;
}
void ReleaseVerifier::add_check(std::string name, bool passed,
std::string detail) {
checks_.push_back({std::move(name), passed, std::move(detail)});
}
bool ReleaseVerifier::green() const {
if (checks_.empty()) return false;
for (const auto& c : checks_) {
if (!c.passed) return false;
}
return true;
}
std::vector<VerifyCheck> ReleaseVerifier::checks() const { return checks_; }
} // namespace molo::example::fw