Allow fetching the log for a specific task

This commit is contained in:
Simon Quigley 2025-01-31 16:00:49 -06:00
parent 7b63ca627e
commit 5ac551f36a
7 changed files with 69 additions and 68 deletions

View File

@ -817,9 +817,15 @@ void CiLogic::sync(std::shared_ptr<PackageConf> pkgconf) {
pkgconf->sync();
}
/**
* Stub logs
*/
std::string CiLogic::get_logs_for_repo_conf(int package_conf_id) {
return "Not implemented";
std::string CiLogic::get_task_log(int task_id) {
QSqlQuery query(get_thread_connection());
query.prepare("SELECT log FROM task WHERE id = ?");
query.bindValue(0, task_id);
if (!ci_query_exec(&query)) qDebug() << "Error getting log for task:" << query.lastError().text();
while (query.next()) {
QString log = query.value("log").toString();
if (!log.isEmpty()) return log.toStdString();
}
return "";
}

View File

@ -81,9 +81,6 @@ class CiLogic {
// Function to enqueue tasks
void enqueue(std::function<void()> task);
// Fetch logs for a specific PackageConf ID
std::string get_logs_for_repo_conf(int package_conf_id);
std::shared_ptr<std::map<std::string, std::shared_ptr<JobStatus>>> get_job_statuses();
std::vector<std::shared_ptr<PackageConf>> get_packageconfs();
std::shared_ptr<PackageConf> get_packageconf_by_id(int id);
@ -98,6 +95,8 @@ class CiLogic {
std::unique_ptr<TaskQueue>& task_queue,
std::shared_ptr<std::map<std::string, std::shared_ptr<JobStatus>>> job_statuses);
std::string get_task_log(int task_id);
std::vector<Release> releases;
std::vector<Package> packages;
std::vector<Branch> branches;

View File

@ -80,13 +80,3 @@ bool LubuntuCI::build_repo(const std::string &repo_name, std::shared_ptr<Log> lo
}
return success;
}
/**
* get_repo_log():
* - Directly opens the repo in /srv/lubuntu-ci/repos/<repo_name>
* - Reads HEAD commit message
*/
std::string LubuntuCI::get_repo_log(const std::string &repo_name)
{
// FIXME: unused
}

View File

@ -42,11 +42,6 @@ public:
*/
bool build_repo(const std::string &repo_name, std::shared_ptr<Log> log = NULL);
/**
* Retrieve the most recent commit log from a named repo.
*/
std::string get_repo_log(const std::string &repo_name);
CiLogic cilogic = CiLogic();
};

View File

@ -559,23 +559,24 @@ bool WebServer::start_server(quint16 port) {
item["upstream_commit"] = upstream_commit_str;
item["upstream_commit_url"] = upstream_commit_url_str;
// For each job in the map, fetch the real task and set a CSS class accordingly.
for (auto const & [job_name, job_ptr] : *job_statuses) {
auto t = r->get_task_by_jobstatus(job_ptr);
if (t) {
std::string css_class = "bg-secondary"; // default
std::string css_class = "bg-secondary";
if (t->finish_time > 0) {
css_class = t->successful ? "bg-success" : "bg-danger";
} else if (t->start_time > 0) {
css_class = "bg-warning"; // started but not finished
css_class = "bg-warning";
} else {
css_class = "bg-info"; // queued but not started
css_class = "bg-info";
}
item[job_name + "_class"] = css_class;
item[job_name + "_id"] = r->id;
} else {
item[job_name + "_class"] = "";
item[job_name + "_id"] = "";
}
}
@ -639,47 +640,6 @@ bool WebServer::start_server(quint16 port) {
});
});
//////////////////////////////////////////
// /logs?repo=foo
//////////////////////////////////////////
http_server_.route("/logs", [this, lubuntuci, job_statuses](const QHttpServerRequest &req) -> QFuture<QHttpServerResponse> {
{
QHttpServerResponse session_response = verify_session_token(req, req.headers());
if (session_response.statusCode() == StatusCodeFound) return QtConcurrent::run([response = std::move(session_response)]() mutable { return std::move(response); });
}
auto query = req.query();
std::string repo = query.queryItemValue("repo").toStdString();
return QtConcurrent::run([=, this]() {
if (repo.empty()) {
std::string msg = "<html><body>No repo specified.</body></html>";
return QHttpServerResponse("text/html", QByteArray(msg.c_str(), (int)msg.size()));
}
std::string log_content = lubuntuci->get_repo_log(repo);
std::map<std::string, std::vector<std::map<std::string, std::string>>> list_context;
std::map<std::string,std::string> context;
context["title"] = "Logs for " + repo;
std::string body;
body += "<h2>Logs: " + repo + "</h2>";
body += "<pre class=\"bg-white p-2\">" + log_content + "</pre>";
context["BODY_CONTENT"] = body;
std::string final_html = TemplateRenderer::render_with_inheritance(
"base.html",
context,
list_context
);
if (final_html.empty()) {
final_html = "<html><body><h1>Log Output</h1><pre>"
+ log_content + "</pre></body></html>";
}
return QHttpServerResponse("text/html", QByteArray(final_html.c_str(), (int)final_html.size()));
});
});
//////////////////////////////////////////
// /pull-selected?repos=<ids>
//////////////////////////////////////////
@ -1004,6 +964,43 @@ bool WebServer::start_server(quint16 port) {
});
});
//////////////////////////////////////////
// /log/<TASK_ID>
//////////////////////////////////////////
http_server_.route("/log/<arg>", [this, lubuntuci, job_statuses](const QString _task_id, const QHttpServerRequest &req) -> QFuture<QHttpServerResponse> {
{
QHttpServerResponse session_response = verify_session_token(req, req.headers());
if (session_response.statusCode() == StatusCodeFound) return QtConcurrent::run([response = std::move(session_response)]() mutable { return std::move(response); });
}
return QtConcurrent::run([=, this]() {
int task_id;
try {
task_id = _task_id.toInt();
if (task_id <= 0) {
std::string msg = "<html><body><h1>Invalid task ID specified.</h1></body></html>";
return QHttpServerResponse("text/html", QByteArray(msg.c_str(), (int)msg.size()));
}
} catch (...) {
std::string msg = "<html><body><h1>Invalid task ID specified.</h1></body></html>";
return QHttpServerResponse("text/html", QByteArray(msg.c_str(), (int)msg.size()));
}
std::string log_content = lubuntuci->cilogic.get_task_log(task_id);
std::map<std::string, std::vector<std::map<std::string, std::string>>> list_context;
std::map<std::string, std::string> context;
context["title"] = "Task Logs";
context["log"] = log_content;
std::string final_html = TemplateRenderer::render_with_inheritance(
"log.html",
context,
list_context
);
return QHttpServerResponse("text/html", QByteArray(final_html.c_str(), (int)final_html.size()));
});
});
{
QSslConfiguration ssl_config = QSslConfiguration::defaultConfiguration();
QFile cert_file("/srv/lubuntu-ci/repos/ci-tools/server.crt");

View File

@ -75,6 +75,7 @@
<td class="w-25">
<div class="justify-content-center align-items-center align-middle {{repo.pull_class}} text-white">
Pull
<a href="/log/{{ repo.pull_id }}" target="_blank"><i class="fa-solid fa-file-lines"></i></a>
</div>
</td>
{% endif %}
@ -83,6 +84,7 @@
<td class="w-25">
<div class="justify-content-center align-items-center align-middle {{repo.tarball_class}} text-white">
Tarball
<a href="/log/{{ repo.tarball_id }}" target="_blank"><i class="fa-solid fa-file-lines"></i></a>
</div>
</td>
{% endif %}
@ -91,6 +93,7 @@
<td class="w-25">
<div class="justify-content-center align-items-center align-middle {{repo.source_build_class}} text-white">
Source Build
<a href="/log/{{ repo.source_build_id }}" target="_blank"><i class="fa-solid fa-file-lines"></i></a>
</div>
</td>
{% endif %}
@ -99,6 +102,7 @@
<td class="w-25">
<div class="justify-content-center align-items-center align-middle {{repo.upload_class}} text-white">
Upload
<a href="/log/{{ repo.upload_id }}" target="_blank"><i class="fa-solid fa-file-lines"></i></a>
</div>
</td>
{% endif %}
@ -108,6 +112,7 @@
<td class="w-25">
<div class="justify-content-center align-items-center align-middle {{repo.source_check_class}} text-white">
Source Check
<a href="/log/{{ repo.source_check_id }}" target="_blank"><i class="fa-solid fa-file-lines"></i></a>
</div>
</td>
{% endif %}
@ -116,6 +121,7 @@
<td class="w-25">
<div class="justify-content-center align-items-center align-middle {{repo.build_check_class}} text-white">
Build Check
<a href="/log/{{ repo.build_check_id }}" target="_blank"><i class="fa-solid fa-file-lines"></i></a>
</div>
</td>
{% endif %}
@ -124,6 +130,7 @@
<td class="w-25">
<div class="justify-content-center align-items-center align-middle {{repo.lintian_class}} text-white">
Lintian
<a href="/log/{{ repo.lintian_id }}" target="_blank"><i class="fa-solid fa-file-lines"></i></a>
</div>
</td>
{% endif %}
@ -132,6 +139,7 @@
<td class="w-25">
<div class="justify-content-center align-items-center align-middle {{repo.britney_class}} text-white">
Britney
<a href="/log/{{ repo.britney_id }}" target="_blank"><i class="fa-solid fa-file-lines"></i></a>
</div>
</td>
{% endif %}

6
templates/log.html Normal file
View File

@ -0,0 +1,6 @@
{% extends "base.html" %}
{% block content %}
<h1>{{PAGE_TITLE}}</h1>
<div class="bg-light font-monospace p-2 rounded overflow-scroll" style="max-height: 100%; max-width: 100%; white-space: pre-wrap;">{{ log }}</div>
{% endblock %}