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(); pkgconf->sync();
} }
/** std::string CiLogic::get_task_log(int task_id) {
* Stub logs QSqlQuery query(get_thread_connection());
*/ query.prepare("SELECT log FROM task WHERE id = ?");
std::string CiLogic::get_logs_for_repo_conf(int package_conf_id) { query.bindValue(0, task_id);
return "Not implemented";
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 // Function to enqueue tasks
void enqueue(std::function<void()> task); 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::shared_ptr<std::map<std::string, std::shared_ptr<JobStatus>>> get_job_statuses();
std::vector<std::shared_ptr<PackageConf>> get_packageconfs(); std::vector<std::shared_ptr<PackageConf>> get_packageconfs();
std::shared_ptr<PackageConf> get_packageconf_by_id(int id); std::shared_ptr<PackageConf> get_packageconf_by_id(int id);
@ -98,6 +95,8 @@ class CiLogic {
std::unique_ptr<TaskQueue>& task_queue, std::unique_ptr<TaskQueue>& task_queue,
std::shared_ptr<std::map<std::string, std::shared_ptr<JobStatus>>> job_statuses); 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<Release> releases;
std::vector<Package> packages; std::vector<Package> packages;
std::vector<Branch> branches; 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; 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); 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(); CiLogic cilogic = CiLogic();
}; };

View File

@ -559,23 +559,24 @@ bool WebServer::start_server(quint16 port) {
item["upstream_commit"] = upstream_commit_str; item["upstream_commit"] = upstream_commit_str;
item["upstream_commit_url"] = upstream_commit_url_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) { for (auto const & [job_name, job_ptr] : *job_statuses) {
auto t = r->get_task_by_jobstatus(job_ptr); auto t = r->get_task_by_jobstatus(job_ptr);
if (t) { if (t) {
std::string css_class = "bg-secondary"; // default std::string css_class = "bg-secondary";
if (t->finish_time > 0) { if (t->finish_time > 0) {
css_class = t->successful ? "bg-success" : "bg-danger"; css_class = t->successful ? "bg-success" : "bg-danger";
} else if (t->start_time > 0) { } else if (t->start_time > 0) {
css_class = "bg-warning"; // started but not finished css_class = "bg-warning";
} else { } else {
css_class = "bg-info"; // queued but not started css_class = "bg-info";
} }
item[job_name + "_class"] = css_class; item[job_name + "_class"] = css_class;
item[job_name + "_id"] = r->id;
} else { } else {
item[job_name + "_class"] = ""; 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> // /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(); QSslConfiguration ssl_config = QSslConfiguration::defaultConfiguration();
QFile cert_file("/srv/lubuntu-ci/repos/ci-tools/server.crt"); QFile cert_file("/srv/lubuntu-ci/repos/ci-tools/server.crt");

View File

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