Skip to content

Commit ac32759

Browse files
committed
Bind issues to deployments
1 parent db7c131 commit ac32759

10 files changed

Lines changed: 49 additions & 91 deletions

File tree

sql/20250612211200_project_issue.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ CREATE TABLE project_issue
44
project_id text NOT NULL REFERENCES project (id) ON DELETE CASCADE,
55
level varchar(255) not null,
66
page_path text,
7-
deployment_id varchar(28) REFERENCES deployment (id) ON DELETE CASCADE,
7+
deployment_id varchar(28) NOT NULL REFERENCES deployment (id) ON DELETE CASCADE,
88
body jsonb not null,
99
created_at timestamp(3) default CURRENT_TIMESTAMP not null
1010
);

src/api/v1/projects.cc

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,12 @@ namespace api::v1 {
493493
root["revision"] = Json::nullValue;
494494
}
495495

496+
const auto issues(co_await global::database->getDeploymentIssues(id));
497+
root["issues"] = toJson(issues);
498+
for (auto &issue: root["issues"]) {
499+
issue["body"] = parseJsonOrThrow(issue["body"].asString());
500+
}
501+
496502
callback(HttpResponse::newHttpJsonResponse(root));
497503
}
498504

@@ -521,24 +527,14 @@ namespace api::v1 {
521527
const std::string id) const {
522528
const auto project(co_await BaseProjectController::getUserProject(req, id));
523529

524-
const auto issues(co_await global::database->getProjectIssues(id));
530+
const auto deployment(co_await global::database->getActiveDeployment(id));
531+
const auto issues =
532+
deployment ? co_await global::database->getDeploymentIssues(deployment->getValueOfId()) : std::vector<ProjectIssue>();
525533
auto root = toJson(issues);
526534
for (auto &issue: root) {
527535
issue["body"] = parseJsonOrThrow(issue["body"].asString());
528536
}
529537

530538
callback(HttpResponse::newHttpJsonResponse(root));
531539
}
532-
533-
Task<> ProjectsController::getIssue(const HttpRequestPtr req, const std::function<void(const HttpResponsePtr &)> callback,
534-
const std::string id) const {
535-
const auto issue(co_await global::database->getProjectIssue(id));
536-
if (!issue) {
537-
throw ApiException(Error::ErrBadRequest, "not_found");
538-
}
539-
540-
const auto project(co_await BaseProjectController::getUserProject(req, issue->project_id));
541-
542-
callback(jsonResponse(*issue));
543-
}
544540
}

src/api/v1/projects.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ namespace api::v1 {
4343
ADD_METHOD_TO(ProjectsController::deleteDeployment, "/api/v1/dev/deployments/{1:id}", drogon::Delete, "AuthFilter");
4444
// Project issues
4545
ADD_METHOD_TO(ProjectsController::getIssues, "/api/v1/dev/projects/{1:id}/issues", drogon::Get, "AuthFilter");
46-
ADD_METHOD_TO(ProjectsController::getIssue, "/api/v1/dev/issues/{1:id}", drogon::Get, "AuthFilter");
4746
METHOD_LIST_END
4847
// clang-format on
4948

@@ -98,9 +97,6 @@ namespace api::v1 {
9897
drogon::Task<> getIssues(drogon::HttpRequestPtr req, std::function<void(const drogon::HttpResponsePtr &)> callback,
9998
std::string id) const;
10099

101-
drogon::Task<> getIssue(drogon::HttpRequestPtr req, std::function<void(const drogon::HttpResponsePtr &)> callback,
102-
std::string id) const;
103-
104100
private:
105101
nlohmann::json processPlatforms(const nlohmann::json &metadata) const;
106102

src/service/database/database.h

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include "models/DataImport.h"
1616
#include "models/Deployment.h"
1717
#include "models/ProjectIssue.h"
18-
#include <service/project_issue.h>
1918

2019
using namespace drogon_model::postgres;
2120

@@ -52,25 +51,6 @@ namespace service {
5251
{"current", d.current}};
5352
}
5453
};
55-
struct ProjectIssueData {
56-
std::string id;
57-
std::string project_id;
58-
std::string level;
59-
std::string page_path;
60-
std::string deployment_id;
61-
nlohmann::json body;
62-
std::string created_at;
63-
64-
friend void to_json(nlohmann::json &j, const ProjectIssueData &d) {
65-
j = nlohmann::json{{"id", d.id},
66-
{"project_id", d.project_id},
67-
{"level", d.level},
68-
{"page_path", d.page_path.empty() ? nullptr : d.page_path},
69-
{"deployment_id", d.deployment_id.empty() ? nullptr : d.deployment_id},
70-
{"body", d.body},
71-
{"created_at", d.created_at}};
72-
}
73-
};
7454

7555
class Database : public DatabaseBase {
7656
public:
@@ -132,13 +112,11 @@ namespace service {
132112
drogon::Task<std::optional<Deployment>> updateDeployment(Deployment deployment) const;
133113
drogon::Task<Error> deactivateDeployments(std::string projectId) const;
134114
drogon::Task<Error> deleteDeployment(std::string id) const;
115+
drogon::Task<bool> hasFailingDeployment(std::string projectId) const;
135116

136117
drogon::Task<std::optional<ProjectIssue>> addProjectIssue(ProjectIssue issue) const;
137-
drogon::Task<std::optional<ProjectIssueData>> getProjectIssue(std::string id) const;
138-
drogon::Task<std::vector<ProjectIssue>> getProjectIssues(std::string projectId) const;
139-
drogon::Task<Error> deleteProjectIssues(std::string projectId) const;
140-
drogon::Task<Error> deleteDeploymentIssues(std::string deploymentId) const;
141-
drogon::Task<std::unordered_map<std::string, int64_t>> getProjectIssueStats(std::string projectId) const;
118+
drogon::Task<std::vector<ProjectIssue>> getDeploymentIssues(std::string deploymentId) const;
119+
drogon::Task<std::unordered_map<std::string, int64_t>> getActiveProjectIssueStats(std::string projectId) const;
142120
private:
143121
drogon::orm::DbClientPtr clientPtr_;
144122
};

src/service/database/database_deployments.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace service {
4646
mapper.limit(1);
4747
co_return co_await mapper.findOne(
4848
Criteria(Deployment::Cols::_project_id, CompareOperator::EQ, projectId) &&
49-
Criteria(Deployment::Cols::_status, CompareOperator::EQ, deploymentStatusToString(DeploymentStatus::SUCCESS)));
49+
Criteria(Deployment::Cols::_status, CompareOperator::EQ, enumToStr(DeploymentStatus::SUCCESS)));
5050
});
5151
co_return res;
5252
}
@@ -58,7 +58,7 @@ namespace service {
5858
co_return co_await mapper.findOne(
5959
Criteria(Deployment::Cols::_project_id, CompareOperator::EQ, projectId)
6060
&& Criteria(Deployment::Cols::_status, CompareOperator::In,
61-
std::vector{deploymentStatusToString(DeploymentStatus::CREATED), deploymentStatusToString(DeploymentStatus::LOADING)}
61+
std::vector{enumToStr(DeploymentStatus::CREATED), enumToStr(DeploymentStatus::LOADING)}
6262
));
6363
});
6464
co_return res;
@@ -101,4 +101,17 @@ namespace service {
101101
});
102102
co_return res.value_or(err);
103103
}
104+
105+
Task<bool> Database::hasFailingDeployment(const std::string projectId) const {
106+
// language=postgresql
107+
static constexpr auto query = "SELECT * FROM deployment \
108+
WHERE project_id = $1 AND status = 'error' \
109+
AND created_at > (SELECT created_at FROM deployment WHERE project_id = $1 AND active)";
110+
111+
const auto [res, err] = co_await handleDatabaseOperation<bool>([projectId](const DbClientPtr &client) -> Task<bool> {
112+
const auto rows = co_await client->execSqlCoro(query, projectId);
113+
co_return rows.size() > 0;
114+
});
115+
co_return res.value_or(false);
116+
}
104117
}

src/service/database/database_issues.cc

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,54 +14,21 @@ namespace service {
1414
co_return res;
1515
}
1616

17-
Task<std::optional<ProjectIssueData>> Database::getProjectIssue(std::string id) const {
18-
const auto [res, err] =
19-
co_await handleDatabaseOperation<ProjectIssueData>([id](const DbClientPtr &client) -> Task<ProjectIssueData> {
20-
CoroMapper<ProjectIssue> mapper(client);
21-
const auto issue = co_await mapper.findByPrimaryKey(id);
22-
co_return ProjectIssueData{.id = issue.getValueOfId(),
23-
.project_id = issue.getValueOfProjectId(),
24-
.level = issue.getValueOfLevel(),
25-
.page_path = issue.getValueOfPagePath(),
26-
.deployment_id = issue.getValueOfDeploymentId(),
27-
.body = nlohmann::json::parse(issue.getValueOfBody()),
28-
.created_at = issue.getValueOfCreatedAt().toCustomFormattedString("%Y-%m-%d")};
29-
});
30-
co_return res;
31-
}
32-
33-
Task<std::vector<ProjectIssue>> Database::getProjectIssues(std::string projectId) const {
17+
Task<std::vector<ProjectIssue>> Database::getDeploymentIssues(const std::string deploymentId) const {
3418
const auto [res, err] = co_await handleDatabaseOperation<std::vector<ProjectIssue>>(
35-
[projectId](const DbClientPtr &client) -> Task<std::vector<ProjectIssue>> {
19+
[deploymentId](const DbClientPtr &client) -> Task<std::vector<ProjectIssue>> {
3620
CoroMapper<ProjectIssue> mapper(client);
3721
mapper.orderBy("array_position(array['error', 'warning'], level)");
38-
co_return co_await mapper.findBy(Criteria(ProjectIssue::Cols::_project_id, CompareOperator::EQ, projectId));
22+
co_return co_await mapper.findBy(Criteria(ProjectIssue::Cols::_deployment_id, CompareOperator::EQ, deploymentId));
3923
});
4024
co_return res.value_or(std::vector<ProjectIssue>{});
4125
}
4226

43-
Task<Error> Database::deleteProjectIssues(std::string projectId) const {
44-
const auto [res, err] = co_await handleDatabaseOperation<Error>([projectId](const DbClientPtr &client) -> Task<Error> {
45-
CoroMapper<ProjectIssue> mapper(client);
46-
co_await mapper.deleteBy(Criteria(ProjectIssue::Cols::_project_id, CompareOperator::EQ, projectId));
47-
co_return Error::Ok;
48-
});
49-
co_return res.value_or(err);
50-
}
51-
52-
Task<Error> Database::deleteDeploymentIssues(std::string deploymentId) const {
53-
const auto [res, err] = co_await handleDatabaseOperation<Error>([deploymentId](const DbClientPtr &client) -> Task<Error> {
54-
CoroMapper<ProjectIssue> mapper(client);
55-
co_await mapper.deleteBy(Criteria(ProjectIssue::Cols::_deployment_id, CompareOperator::EQ, deploymentId));
56-
co_return Error::Ok;
57-
});
58-
co_return res.value_or(err);
59-
}
60-
61-
Task<std::unordered_map<std::string, int64_t>> Database::getProjectIssueStats(std::string projectId) const {
27+
Task<std::unordered_map<std::string, int64_t>> Database::getActiveProjectIssueStats(std::string projectId) const {
6228
// language=postgresql
6329
static constexpr auto query = "SELECT level, count(level) AS count FROM project_issue \
6430
WHERE project_id = $1 \
31+
AND deployment_id = (SELECT id FROM deployment d WHERE d.project_id = $1 AND d.active) \
6532
GROUP BY level";
6633

6734
const auto [res, err] = co_await handleDatabaseOperation<std::unordered_map<std::string, int64_t>>(

src/service/deployment.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include "deployment.h"
22

33
namespace service {
4-
std::string deploymentStatusToString(const DeploymentStatus status) {
4+
std::string enumToStr(const DeploymentStatus status) {
55
switch (status) {
66
case DeploymentStatus::CREATED:
77
return "create";

src/service/deployment.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ namespace service {
1010
SUCCESS,
1111
ERROR
1212
};
13-
std::string deploymentStatusToString(DeploymentStatus status);
13+
std::string enumToStr(DeploymentStatus status);
1414
}

src/service/resolved.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,8 +486,11 @@ namespace service {
486486
}
487487
}
488488

489-
const auto issueStats = co_await global::database->getProjectIssueStats(project_.getValueOfId());
489+
const auto issueStats = co_await global::database->getActiveProjectIssueStats(project_.getValueOfId());
490490
projectJson["issue_stats"] = unparkourJson(nlohmann::json(issueStats));
491+
492+
const auto hasFailingDeployment = co_await global::database->hasFailingDeployment(project_.getValueOfId());
493+
projectJson["has_failing_deployment"] = hasFailingDeployment;
491494
}
492495

493496
co_return projectJson;

src/service/storage.cc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <spdlog/sinks/stdout_color_sinks.h>
1717

1818
#include "deployment.h"
19+
#include "project_issue.h"
1920

2021
#define TEMP_DIR ".temp"
2122
#define LATEST_VERSION "latest"
@@ -530,7 +531,7 @@ namespace service {
530531

531532
logger->info("Setting up project");
532533

533-
deployment.setStatus(deploymentStatusToString(DeploymentStatus::LOADING));
534+
deployment.setStatus(enumToStr(DeploymentStatus::LOADING));
534535
co_await global::database->updateDeployment(deployment);
535536

536537
const auto [repo, cloneError] = co_await gitCloneProject(project, clonePath, project.getValueOfSourceBranch(), logger);
@@ -608,7 +609,7 @@ namespace service {
608609
Deployment tmpDep;
609610
tmpDep.setId(project.getValueOfId());
610611
tmpDep.setProjectId(project.getValueOfId());
611-
tmpDep.setStatus(deploymentStatusToString(DeploymentStatus::CREATED));
612+
tmpDep.setStatus(enumToStr(DeploymentStatus::CREATED));
612613
tmpDep.setSourceRepo(project.getValueOfSourceRepo());
613614
tmpDep.setSourceBranch(project.getValueOfSourceBranch());
614615
tmpDep.setSourcePath(project.getValueOfSourcePath());
@@ -632,15 +633,15 @@ namespace service {
632633

633634
global::connections->broadcast(project.getValueOfId(), WS_SUCCESS);
634635

635-
deployment.setStatus(deploymentStatusToString(DeploymentStatus::SUCCESS));
636+
deployment.setStatus(enumToStr(DeploymentStatus::SUCCESS));
636637
} else {
637638
projectLogger->error("!!================================!!");
638639
projectLogger->error("!! Project setup failed !!");
639640
projectLogger->error("!!================================!!");
640641

641642
global::connections->broadcast(project.getValueOfId(), WS_ERROR);
642643

643-
deployment.setStatus(deploymentStatusToString(DeploymentStatus::ERROR));
644+
deployment.setStatus(enumToStr(DeploymentStatus::ERROR));
644645
}
645646

646647
co_await global::database->updateDeployment(deployment);
@@ -730,7 +731,11 @@ namespace service {
730731
co_return ProjectStatus::UNKNOWN;
731732
}
732733

733-
if (const auto issues = co_await global::database->getProjectIssueStats(project.getValueOfId());
734+
if (co_await global::database->hasFailingDeployment(project.getValueOfId())) {
735+
co_return ProjectStatus::AT_RISK;
736+
}
737+
738+
if (const auto issues = co_await global::database->getActiveProjectIssueStats(project.getValueOfId());
734739
issues.contains(enumToStr(ProjectIssueLevel::ERROR))) {
735740
co_return ProjectStatus::AT_RISK;
736741
}

0 commit comments

Comments
 (0)