mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-11-12 11:33:42 +00:00
Compare commits
2 Commits
471b1c1331
...
b83df9d2c5
| Author | SHA1 | Date | |
|---|---|---|---|
| b83df9d2c5 | |||
| f2ea76aab9 |
@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
function createAlert(title, message, clz, action, id) {
|
function createAlert(title, message, clz, action, id) {
|
||||||
id ??= md5(title + message); // MD5 id from the content
|
id ??= md5(title + message); // MD5 id from the content
|
||||||
if (alertPlaceholder.querySelector(`#alert-${id}`)) return; // check if there are duplicates
|
if (alertPlaceholder.querySelector(`#alert-${id}`)) {
|
||||||
|
return; // check if there are duplicates
|
||||||
|
}
|
||||||
|
|
||||||
const wrapper = document.createElement("div");
|
const wrapper = document.createElement("div");
|
||||||
wrapper.id = `alert-${id}`;
|
wrapper.id = `alert-${id}`;
|
||||||
|
|||||||
@ -51,6 +51,87 @@
|
|||||||
const dashboardPackagesCountChartCanvas = document.getElementById("dashboard-packages-count-chart");
|
const dashboardPackagesCountChartCanvas = document.getElementById("dashboard-packages-count-chart");
|
||||||
let dashboardPackagesCountChart = null;
|
let dashboardPackagesCountChart = null;
|
||||||
|
|
||||||
|
function statusLoad() {
|
||||||
|
const badgeClass = status => {
|
||||||
|
if (status === "pending") return "btn-outline-warning";
|
||||||
|
if (status === "building") return "btn-outline-warning";
|
||||||
|
if (status === "failed") return "btn-outline-danger";
|
||||||
|
if (status === "success") return "btn-outline-success";
|
||||||
|
return "btn-outline-secondary";
|
||||||
|
};
|
||||||
|
|
||||||
|
makeRequest(
|
||||||
|
"/api/v1/status",
|
||||||
|
{
|
||||||
|
query: {
|
||||||
|
architecture: repository.architecture,
|
||||||
|
repository: repository.repository,
|
||||||
|
},
|
||||||
|
convert: response => response.json(),
|
||||||
|
},
|
||||||
|
data => {
|
||||||
|
versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`;
|
||||||
|
|
||||||
|
dashboardButton.classList.remove(...dashboardButton.classList);
|
||||||
|
dashboardButton.classList.add("btn");
|
||||||
|
dashboardButton.classList.add(badgeClass(data.status.status));
|
||||||
|
|
||||||
|
dashboardModalHeader.classList.remove(...dashboardModalHeader.classList);
|
||||||
|
dashboardModalHeader.classList.add("modal-header");
|
||||||
|
headerClass(data.status.status).forEach(clz => dashboardModalHeader.classList.add(clz));
|
||||||
|
|
||||||
|
dashboardName.textContent = data.repository;
|
||||||
|
dashboardArchitecture.textContent = data.architecture;
|
||||||
|
dashboardStatus.textContent = data.status.status;
|
||||||
|
dashboardStatusTimestamp.textContent = new Date(1000 * data.status.timestamp).toISOStringShort();
|
||||||
|
|
||||||
|
if (dashboardPackagesStatusesChart) {
|
||||||
|
const labels = [
|
||||||
|
"unknown",
|
||||||
|
"pending",
|
||||||
|
"building",
|
||||||
|
"failed",
|
||||||
|
"success",
|
||||||
|
];
|
||||||
|
dashboardPackagesStatusesChart.config.data = {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: "packages in status",
|
||||||
|
data: labels.map(label => data.packages[label]),
|
||||||
|
backgroundColor: [
|
||||||
|
"rgb(55, 58, 60)",
|
||||||
|
"rgb(255, 117, 24)",
|
||||||
|
"rgb(255, 117, 24)",
|
||||||
|
"rgb(255, 0, 57)",
|
||||||
|
"rgb(63, 182, 24)", // copy-paste from current style
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
};
|
||||||
|
dashboardPackagesStatusesChart.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dashboardPackagesCountChart) {
|
||||||
|
dashboardPackagesCountChart.config.data = {
|
||||||
|
labels: ["packages"],
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: "archives",
|
||||||
|
data: [data.stats.packages],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "bases",
|
||||||
|
data: [data.stats.bases],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
dashboardPackagesCountChart.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboardCanvas.hidden = data.status.total > 0;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ready(_ => {
|
ready(_ => {
|
||||||
dashboardPackagesStatusesChart = new Chart(dashboardPackagesStatusesChartCanvas, {
|
dashboardPackagesStatusesChart = new Chart(dashboardPackagesStatusesChartCanvas, {
|
||||||
type: "pie",
|
type: "pie",
|
||||||
|
|||||||
@ -97,7 +97,7 @@
|
|||||||
<input id="package-info-refresh-input" type="checkbox" class="form-check-input" value="" checked>
|
<input id="package-info-refresh-input" type="checkbox" class="form-check-input" value="" checked>
|
||||||
<label for="package-info-refresh-input" class="form-check-label">update pacman databases</label>
|
<label for="package-info-refresh-input" class="form-check-label">update pacman databases</label>
|
||||||
|
|
||||||
<button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()" data-bs-dismiss="modal"><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button>
|
<button id="package-info-update-button" type="submit" class="btn btn-success" onclick="packageInfoUpdate()"><i class="bi bi-play"></i><span class="d-none d-sm-inline"> update</span></button>
|
||||||
<button id="package-info-remove-button" type="submit" class="btn btn-danger" onclick="packageInfoRemove()" data-bs-dismiss="modal"><i class="bi bi-trash"></i><span class="d-none d-sm-inline"> remove</span></button>
|
<button id="package-info-remove-button" type="submit" class="btn btn-danger" onclick="packageInfoRemove()" data-bs-dismiss="modal"><i class="bi bi-trash"></i><span class="d-none d-sm-inline"> remove</span></button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if autorefresh_intervals %}
|
{% if autorefresh_intervals %}
|
||||||
@ -315,6 +315,69 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadLogs(packageBase, onFailure) {
|
function loadLogs(packageBase, onFailure) {
|
||||||
|
const sortFn = (left, right) => left.process_id.localeCompare(right.process_id) || left.version.localeCompare(right.version);
|
||||||
|
const compareFn = (left, right) => left.process_id === right.process_id && left.version === right.version;
|
||||||
|
|
||||||
|
makeRequest(
|
||||||
|
`/api/v2/packages/${packageBase}/logs`,
|
||||||
|
{
|
||||||
|
query: {
|
||||||
|
architecture: repository.architecture,
|
||||||
|
head: true,
|
||||||
|
repository: repository.repository,
|
||||||
|
},
|
||||||
|
convert: response => response.json(),
|
||||||
|
},
|
||||||
|
data => {
|
||||||
|
const currentVersions = Array.from(packageInfoLogsVersions.children)
|
||||||
|
.map(el => {
|
||||||
|
return {
|
||||||
|
process_id: el.dataset.processId,
|
||||||
|
version: el.dataset.version,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort(sortFn);
|
||||||
|
const newVersions = data
|
||||||
|
.map(el => {
|
||||||
|
return {
|
||||||
|
process_id: el.process_id,
|
||||||
|
version: el.version,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort(sortFn);
|
||||||
|
|
||||||
|
if (currentVersions.equals(newVersions, compareFn))
|
||||||
|
loadLogsActive(packageBase);
|
||||||
|
else
|
||||||
|
loadLogsAll(packageBase, onFailure);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadLogsActive(packageBase) {
|
||||||
|
const activeLogSelector = packageInfoLogsVersions.querySelector(".active");
|
||||||
|
|
||||||
|
if (activeLogSelector) {
|
||||||
|
makeRequest(
|
||||||
|
`/api/v2/packages/${packageBase}/logs`,
|
||||||
|
{
|
||||||
|
query: {
|
||||||
|
architecture: repository.architecture,
|
||||||
|
repository: repository.repository,
|
||||||
|
version: activeLogSelector.dataset.version,
|
||||||
|
process_id: activeLogSelector.dataset.processId,
|
||||||
|
},
|
||||||
|
convert: response => response.json(),
|
||||||
|
},
|
||||||
|
data => {
|
||||||
|
activeLogSelector.dataset.logs = convertLogs(data);
|
||||||
|
activeLogSelector.click();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadLogsAll(packageBase, onFailure) {
|
||||||
makeRequest(
|
makeRequest(
|
||||||
`/api/v2/packages/${packageBase}/logs`,
|
`/api/v2/packages/${packageBase}/logs`,
|
||||||
{
|
{
|
||||||
@ -440,29 +503,6 @@
|
|||||||
packagesAdd(packageBase, [], repository, {refresh: packageInfoRefreshInput.checked});
|
packagesAdd(packageBase, [], repository, {refresh: packageInfoRefreshInput.checked});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadActiveLogs(packageBase) {
|
|
||||||
const activeLogSelector = packageInfoLogsVersions.querySelector(".active");
|
|
||||||
|
|
||||||
if (activeLogSelector) {
|
|
||||||
makeRequest(
|
|
||||||
`/api/v2/packages/${packageBase}/logs`,
|
|
||||||
{
|
|
||||||
query: {
|
|
||||||
architecture: repository.architecture,
|
|
||||||
repository: repository.repository,
|
|
||||||
version: activeLogSelector.dataset.version,
|
|
||||||
process_id: activeLogSelector.dataset.processId,
|
|
||||||
},
|
|
||||||
convert: response => response.json(),
|
|
||||||
},
|
|
||||||
data => {
|
|
||||||
activeLogSelector.dataset.logs = convertLogs(data);
|
|
||||||
activeLogSelector.click();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPackageInfo(packageBase) {
|
function showPackageInfo(packageBase) {
|
||||||
const isPackageBaseSet = packageBase !== undefined;
|
const isPackageBaseSet = packageBase !== undefined;
|
||||||
if (isPackageBaseSet) {
|
if (isPackageBaseSet) {
|
||||||
@ -502,7 +542,7 @@
|
|||||||
const packageBase = packageInfoModal.dataset.package;
|
const packageBase = packageInfoModal.dataset.package;
|
||||||
// we only poll status and logs here
|
// we only poll status and logs here
|
||||||
loadPackage(packageBase);
|
loadPackage(packageBase);
|
||||||
reloadActiveLogs(packageBase);
|
loadLogs(packageBase);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,41 @@
|
|||||||
return table.bootstrapTable("getSelections").map(row => row.id);
|
return table.bootstrapTable("getSelections").map(row => row.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function packagesLoad(onFailure) {
|
||||||
|
makeRequest(
|
||||||
|
"/api/v1/packages",
|
||||||
|
{
|
||||||
|
query: {
|
||||||
|
architecture: repository.architecture,
|
||||||
|
repository: repository.repository,
|
||||||
|
},
|
||||||
|
convert: response => response.json(),
|
||||||
|
},
|
||||||
|
data => {
|
||||||
|
const payload = data
|
||||||
|
.map(description => {
|
||||||
|
const package_base = description.package.base;
|
||||||
|
const web_url = description.package.remote.web_url;
|
||||||
|
return {
|
||||||
|
id: package_base,
|
||||||
|
base: web_url ? safeLink(web_url, package_base, package_base).outerHTML : safe(package_base),
|
||||||
|
version: safe(description.package.version),
|
||||||
|
packager: description.package.packager ? safe(description.package.packager) : "",
|
||||||
|
packages: listToTable(Object.keys(description.package.packages)),
|
||||||
|
groups: listToTable(extractListProperties(description.package, "groups")),
|
||||||
|
licenses: listToTable(extractListProperties(description.package, "licenses")),
|
||||||
|
timestamp: new Date(1000 * description.status.timestamp).toISOStringShort(),
|
||||||
|
status: description.status.status,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
updateTable(table, payload);
|
||||||
|
table.bootstrapTable("hideLoading");
|
||||||
|
},
|
||||||
|
onFailure,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function packagesRemove(packages) {
|
function packagesRemove(packages) {
|
||||||
packages = packages ?? getSelection();
|
packages = packages ?? getSelection();
|
||||||
const onSuccess = update => `Packages ${update} have been removed`;
|
const onSuccess = update => `Packages ${update} have been removed`;
|
||||||
@ -90,51 +125,9 @@
|
|||||||
doPackageAction("/api/v1/service/update", [], repository, onSuccess, onFailure, parameters);
|
doPackageAction("/api/v1/service/update", [], repository, onSuccess, onFailure, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
function reload(silent) {
|
function reload() {
|
||||||
if (!silent) {
|
|
||||||
table.bootstrapTable("showLoading");
|
table.bootstrapTable("showLoading");
|
||||||
}
|
const onFailure = error => {
|
||||||
|
|
||||||
const badgeClass = status => {
|
|
||||||
if (status === "pending") return "btn-outline-warning";
|
|
||||||
if (status === "building") return "btn-outline-warning";
|
|
||||||
if (status === "failed") return "btn-outline-danger";
|
|
||||||
if (status === "success") return "btn-outline-success";
|
|
||||||
return "btn-outline-secondary";
|
|
||||||
};
|
|
||||||
|
|
||||||
makeRequest(
|
|
||||||
"/api/v1/packages",
|
|
||||||
{
|
|
||||||
query: {
|
|
||||||
architecture: repository.architecture,
|
|
||||||
repository: repository.repository,
|
|
||||||
},
|
|
||||||
convert: response => response.json(),
|
|
||||||
},
|
|
||||||
data => {
|
|
||||||
const payload = data
|
|
||||||
.map(description => {
|
|
||||||
const package_base = description.package.base;
|
|
||||||
const web_url = description.package.remote.web_url;
|
|
||||||
return {
|
|
||||||
id: package_base,
|
|
||||||
base: web_url ? safeLink(web_url, package_base, package_base).outerHTML : safe(package_base),
|
|
||||||
version: safe(description.package.version),
|
|
||||||
packager: description.package.packager ? safe(description.package.packager) : "",
|
|
||||||
packages: listToTable(Object.keys(description.package.packages)),
|
|
||||||
groups: listToTable(extractListProperties(description.package, "groups")),
|
|
||||||
licenses: listToTable(extractListProperties(description.package, "licenses")),
|
|
||||||
timestamp: new Date(1000 * description.status.timestamp).toISOStringShort(),
|
|
||||||
status: description.status.status,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
updateTable(table, payload);
|
|
||||||
table.bootstrapTable("hideLoading");
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
if (!silent) {
|
|
||||||
if ((error.status === 401) || (error.status === 403)) {
|
if ((error.status === 401) || (error.status === 403)) {
|
||||||
// authorization error
|
// authorization error
|
||||||
const text = "In order to see statuses you must login first.";
|
const text = "In order to see statuses you must login first.";
|
||||||
@ -146,80 +139,10 @@
|
|||||||
const message = details => `Could not load list of packages: ${details}`;
|
const message = details => `Could not load list of packages: ${details}`;
|
||||||
showFailure("Load failure", message, error);
|
showFailure("Load failure", message, error);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
makeRequest(
|
|
||||||
"/api/v1/status",
|
|
||||||
{
|
|
||||||
query: {
|
|
||||||
architecture: repository.architecture,
|
|
||||||
repository: repository.repository,
|
|
||||||
},
|
|
||||||
convert: response => response.json(),
|
|
||||||
},
|
|
||||||
data => {
|
|
||||||
versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`;
|
|
||||||
|
|
||||||
dashboardButton.classList.remove(...dashboardButton.classList);
|
|
||||||
dashboardButton.classList.add("btn");
|
|
||||||
dashboardButton.classList.add(badgeClass(data.status.status));
|
|
||||||
|
|
||||||
dashboardModalHeader.classList.remove(...dashboardModalHeader.classList);
|
|
||||||
dashboardModalHeader.classList.add("modal-header");
|
|
||||||
headerClass(data.status.status).forEach(clz => dashboardModalHeader.classList.add(clz));
|
|
||||||
|
|
||||||
dashboardName.textContent = data.repository;
|
|
||||||
dashboardArchitecture.textContent = data.architecture;
|
|
||||||
dashboardStatus.textContent = data.status.status;
|
|
||||||
dashboardStatusTimestamp.textContent = new Date(1000 * data.status.timestamp).toISOStringShort();
|
|
||||||
|
|
||||||
if (dashboardPackagesStatusesChart) {
|
|
||||||
const labels = [
|
|
||||||
"unknown",
|
|
||||||
"pending",
|
|
||||||
"building",
|
|
||||||
"failed",
|
|
||||||
"success",
|
|
||||||
];
|
|
||||||
dashboardPackagesStatusesChart.config.data = {
|
|
||||||
labels: labels,
|
|
||||||
datasets: [{
|
|
||||||
label: "packages in status",
|
|
||||||
data: labels.map(label => data.packages[label]),
|
|
||||||
backgroundColor: [
|
|
||||||
"rgb(55, 58, 60)",
|
|
||||||
"rgb(255, 117, 24)",
|
|
||||||
"rgb(255, 117, 24)",
|
|
||||||
"rgb(255, 0, 57)",
|
|
||||||
"rgb(63, 182, 24)", // copy-paste from current style
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
};
|
};
|
||||||
dashboardPackagesStatusesChart.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dashboardPackagesCountChart) {
|
packagesLoad(onFailure);
|
||||||
dashboardPackagesCountChart.config.data = {
|
statusLoad();
|
||||||
labels: ["packages"],
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: "archives",
|
|
||||||
data: [data.stats.packages],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "bases",
|
|
||||||
data: [data.stats.bases],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
dashboardPackagesCountChart.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
dashboardCanvas.hidden = data.status.total > 0;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectRepository() {
|
function selectRepository() {
|
||||||
@ -243,7 +166,8 @@
|
|||||||
tableAutoReloadTask = toggleAutoReload(tableAutoReloadButton, interval, tableAutoReloadInput, _ => {
|
tableAutoReloadTask = toggleAutoReload(tableAutoReloadButton, interval, tableAutoReloadInput, _ => {
|
||||||
if (!dashboardModal.classList.contains("show") &&
|
if (!dashboardModal.classList.contains("show") &&
|
||||||
!hasActiveDropdown()) {
|
!hasActiveDropdown()) {
|
||||||
reload(true);
|
packagesLoad();
|
||||||
|
statusLoad();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -218,6 +218,21 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array.prototype.equals = function (right, comparator) {
|
||||||
|
let index = this.length;
|
||||||
|
if (index !== right.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (index--) {
|
||||||
|
if (!comparator(this[index], right[index])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Date.prototype.toISOStringShort = function () {
|
Date.prototype.toISOStringShort = function () {
|
||||||
const pad = number => String(number).padStart(2, "0");
|
const pad = number => String(number).padStart(2, "0");
|
||||||
return `${this.getFullYear()}-${pad(this.getMonth() + 1)}-${pad(this.getDate())} ${pad(this.getHours())}:${pad(this.getMinutes())}:${pad(this.getSeconds())}`;
|
return `${this.getFullYear()}-${pad(this.getMonth() + 1)}-${pad(this.getDate())} ${pad(this.getHours())}:${pad(this.getMinutes())}:${pad(this.getSeconds())}`;
|
||||||
|
|||||||
@ -27,6 +27,9 @@ class LogsSearchSchema(PaginationSchema):
|
|||||||
request log search schema
|
request log search schema
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
head = fields.Boolean(metadata={
|
||||||
|
"description": "Return versions only without fetching logs themselves",
|
||||||
|
})
|
||||||
version = fields.String(metadata={
|
version = fields.String(metadata={
|
||||||
"description": "Package version to search",
|
"description": "Package version to search",
|
||||||
"example": __version__,
|
"example": __version__,
|
||||||
|
|||||||
@ -17,7 +17,10 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import itertools
|
||||||
|
|
||||||
from aiohttp.web import Response, json_response
|
from aiohttp.web import Response, json_response
|
||||||
|
from dataclasses import replace
|
||||||
from typing import ClassVar
|
from typing import ClassVar
|
||||||
|
|
||||||
from ahriman.models.user_access import UserAccess
|
from ahriman.models.user_access import UserAccess
|
||||||
@ -28,7 +31,8 @@ from ahriman.web.views.status_view_guard import StatusViewGuard
|
|||||||
|
|
||||||
|
|
||||||
class LogsView(StatusViewGuard, BaseView):
|
class LogsView(StatusViewGuard, BaseView):
|
||||||
"""
|
""" else:
|
||||||
|
|
||||||
package logs web view
|
package logs web view
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@ -66,5 +70,14 @@ class LogsView(StatusViewGuard, BaseView):
|
|||||||
|
|
||||||
logs = self.service(package_base=package_base).package_logs_get(package_base, version, process, limit, offset)
|
logs = self.service(package_base=package_base).package_logs_get(package_base, version, process, limit, offset)
|
||||||
|
|
||||||
|
head = self.request.query.get("head", "false")
|
||||||
|
# pylint: disable=protected-access
|
||||||
|
if self.configuration._convert_to_boolean(head): # type: ignore[attr-defined]
|
||||||
|
# logs should be sorted already
|
||||||
|
logs = [
|
||||||
|
replace(next(log_records), message="") # remove messages
|
||||||
|
for _, log_records in itertools.groupby(logs, lambda log_record: log_record.log_record_id)
|
||||||
|
]
|
||||||
|
|
||||||
response = [log_record.view() for log_record in logs]
|
response = [log_record.view() for log_record in logs]
|
||||||
return json_response(response)
|
return json_response(response)
|
||||||
|
|||||||
@ -139,3 +139,41 @@ async def test_get_not_found(client: TestClient, package_ahriman: Package) -> No
|
|||||||
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs")
|
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs")
|
||||||
assert response.status == 404
|
assert response.status == 404
|
||||||
assert not response_schema.validate(await response.json())
|
assert not response_schema.validate(await response.json())
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_head(client: TestClient, package_ahriman: Package) -> None:
|
||||||
|
"""
|
||||||
|
must return only versions if head parameter is set
|
||||||
|
"""
|
||||||
|
await client.post(f"/api/v1/packages/{package_ahriman.base}",
|
||||||
|
json={"status": BuildStatusEnum.Success.value, "package": package_ahriman.view()})
|
||||||
|
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||||
|
json={"created": 42.0, "message": "message 1", "version": "42"})
|
||||||
|
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||||
|
json={"created": 43.0, "message": "message 2", "version": "42"})
|
||||||
|
await client.post(f"/api/v1/packages/{package_ahriman.base}/logs",
|
||||||
|
json={"created": 44.0, "message": "message 3", "version": "43"})
|
||||||
|
request_schema = pytest.helpers.schema_request(LogsView.get, location="querystring")
|
||||||
|
response_schema = pytest.helpers.schema_response(LogsView.get)
|
||||||
|
|
||||||
|
payload = {"head": "true"}
|
||||||
|
assert not request_schema.validate(payload)
|
||||||
|
response = await client.get(f"/api/v2/packages/{package_ahriman.base}/logs", params=payload)
|
||||||
|
assert response.status == 200
|
||||||
|
|
||||||
|
logs = await response.json()
|
||||||
|
assert not response_schema.validate(logs)
|
||||||
|
assert logs == [
|
||||||
|
{
|
||||||
|
"created": 42.0,
|
||||||
|
"message": "",
|
||||||
|
"version": "42",
|
||||||
|
"process_id": LogRecordId.DEFAULT_PROCESS_ID,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"created": 44.0,
|
||||||
|
"message": "",
|
||||||
|
"version": "43",
|
||||||
|
"process_id": LogRecordId.DEFAULT_PROCESS_ID,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user