Update program

- Now tracks Created files
- Error handling
This commit is contained in:
Tiago Garcia 2024-01-27 16:33:12 +00:00 committed by Tiago Garcia
parent 37c3cb53e4
commit 1f9e0d863e
Signed by: TiagoRG
GPG Key ID: DFCD48E3F420DB42
3 changed files with 78 additions and 43 deletions

3
.gitignore vendored
View File

@ -3,5 +3,4 @@ CMakeFiles/
CMakeCache.txt CMakeCache.txt
Makefile Makefile
cmake_install.cmake cmake_install.cmake
gh-wh-handler bin/
config.json

View File

@ -33,7 +33,7 @@ The configuration file should be a JSON file with the following format:
"repo_full_name": { "repo_full_name": {
"branch": "target_branch", "branch": "target_branch",
"files": { "files": {
"remote_path": "local_path", "remote_path": "local_path"
} }
} }
}, },
@ -45,4 +45,4 @@ The configuration file should be a JSON file with the following format:
## Endpoint ## Endpoint
Currently the only endpoint for the application is /update-files Currently, the only endpoint for the application is /update-files

114
main.cpp
View File

@ -5,15 +5,23 @@
#include <crow/app.h> #include <crow/app.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
void signal_handler(const int signum) {
// std::cout << "Interrupt signal (" << signum << ") received.\n";
std::cout << "Exiting..." << std::endl;
std::exit(signum);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
// Check for config file argument, exit if it's not there // Check for config file argument, exit if it's not there
if (argc != 2) { if (argc > 2) {
std::cerr << "Usage: " << 0[argv] << " <config_file>" << std::endl; std::cerr << "Usage: " << 0[argv] << " <config_file>" << std::endl;
return 1; return 1;
} }
std::string config_file_path = argc == 2 ? 1[argv] : "/etc/gh_wh_handler/config.json";
// Open config file, exit if it fails // Open config file, exit if it fails
std::ifstream config_file(1[argv]); std::ifstream config_file(config_file_path);
if (!config_file.is_open()) { if (!config_file.is_open()) {
std::cerr << "Failed to open config.json" << std::endl; std::cerr << "Failed to open config.json" << std::endl;
return 1; return 1;
@ -57,24 +65,36 @@ int main(int argc, char **argv) {
} }
try { try {
std::string ref;
std::string repo;
bool is_private;
std::string token;
// Parse the payload // Parse the payload
std::string ref = payload["ref"]; try {
size_t last_slash = ref.find_last_of('/'); ref = payload["ref"];
if (last_slash != std::string::npos && last_slash + 1 < ref.length()) if (size_t last_slash = ref.find_last_of('/'); last_slash != std::string::npos && last_slash + 1 < ref.length())
ref = ref.substr(last_slash + 1); ref = ref.substr(last_slash + 1);
std::string repo = payload["repository"]["full_name"]; repo = payload["repository"]["full_name"];
bool is_private = payload["repository"]["private"]; is_private = payload["repository"]["private"];
std::string token = std::string(); token = std::string();
if (is_private) { if (is_private) {
if (tokens.find(repo) == tokens.end()) { if (tokens.find(repo) == tokens.end()) {
printf("No token configured for private repo %s\n", repo.c_str()); printf("No token configured for private repo %s\n", repo.c_str());
nlohmann::json response = { nlohmann::json response = {
{"status", 403}, {"status", 403},
{"error", "No token configured for private repo"} {"error", "No token configured for private repo"}
}; };
return crow::response(403, response.dump()); return crow::response(403, response.dump());
}
token = tokens[repo];
} }
token = tokens[repo]; } catch (const std::exception &e) {
std::cerr << "Error parsing payload: " << e.what() << std::endl;
nlohmann::json response = {
{"status", 400},
{"error", "Invalid JSON payload"}
};
return crow::response(400, response.dump());
} }
printf("Received push to %s:%s (private: %s)\n", repo.c_str(), ref.c_str(), is_private ? "true" : "false"); printf("Received push to %s:%s (private: %s)\n", repo.c_str(), ref.c_str(), is_private ? "true" : "false");
@ -93,8 +113,7 @@ int main(int argc, char **argv) {
nlohmann::json repo_data; nlohmann::json repo_data;
bool is_valid_branch = false; bool is_valid_branch = false;
for (auto c_repo = repos.begin(); c_repo != repos.end(); ++c_repo) { for (auto c_repo = repos.begin(); c_repo != repos.end(); ++c_repo) {
std::string c_repo_name = c_repo.key(); if (const std::string &c_repo_name = c_repo.key(); c_repo_name != repo) continue;
if (c_repo_name != repo) continue;
if (c_repo.value()["branch"] != ref) continue; if (c_repo.value()["branch"] != ref) continue;
is_valid_branch = true; is_valid_branch = true;
repo_data = c_repo.value(); repo_data = c_repo.value();
@ -119,33 +138,46 @@ int main(int argc, char **argv) {
return crow::response(404, response.dump()); return crow::response(404, response.dump());
} }
// Get list with modified files
std::vector<std::vector<std::string>> modified_files;
for (auto &commit : payload["commits"]) {
for (auto &file : commit["modified"]) {
std::string file_path = file;
if (repos[repo]["files"].find(file_path) == repos[repo]["files"].end()) continue;
std::vector<std::string> file_data = {file_path, "modified"};
modified_files.push_back(file_data);
}
for (auto &file : commit["added"]) {
std::string file_path = file;
if (repos[repo]["files"].find(file_path) == repos[repo]["files"].end()) continue;
std::vector<std::string> file_data = {file_path, "added"};
modified_files.push_back(file_data);
}
}
// Download files // Download files
nlohmann::json response = { nlohmann::json response = {
{"status", 200}, {"status", 200},
{"file_count", 0}, {"file_count", 0},
{"updated", nlohmann::json::array()} {"updated", nlohmann::json::array()}
}; };
for (auto &commit : payload["commits"]) { for (std::vector<std::string> &file_data : modified_files) {
for (auto &file : commit["modified"]) { std::string file_path = file_data[0];
std::string file_path = file;
if (repos[repo]["files"].find(file_path) == repos[repo]["files"].end()) continue;
std::string path = repos[repo]["files"][file_path]; std::string path = repos[repo]["files"][file_path];
try { try {
std::filesystem::create_directories(path.substr(0, path.find_last_of('/'))); std::filesystem::create_directories(path.substr(0, path.find_last_of('/')));
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << "Failed to create directories for " << path << ": " << e.what() << std::endl; std::cerr << "Failed to create directories for " << path << ": " << e.what() << std::endl;
continue; continue;
}
std::string command = "curl -s https://raw.githubusercontent.com/" + repo + "/" + ref + "/" + file_path + " -o " + path;
if (is_private)
command += " -H 'Authorization: token " + token + "'";
std::system(command.c_str());
printf("Updated %s\n", path.c_str());
response["file_count"] = response["file_count"].get<int>() + 1;
response["updated"].push_back(file_path);
} }
std::string command = "curl -s https://raw.githubusercontent.com/" + repo + "/" + ref + "/" + file_path + " -o " + path;
if (is_private) command += " -H 'Authorization: token " + token + "'";
std::system(command.c_str());
printf("%s %s\n", file_data[1] == "added" ? "Created" : "Updated", path.c_str());
response["file_count"] = response["file_count"].get<int>() + 1;
response["updated"].push_back(file_path);
} }
return crow::response(200, response.dump()); return crow::response(200, response.dump());
@ -155,5 +187,9 @@ int main(int argc, char **argv) {
} }
}); });
std::signal(SIGINT, signal_handler);
app.port(port).multithreaded().run(); app.port(port).multithreaded().run();
return 0;
} }