diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6098e1f --- /dev/null +++ b/.clang-format @@ -0,0 +1,41 @@ +--- +# We'll use defaults from the LLVM style, but with 4 columns indentation. +BasedOnStyle: LLVM +IndentWidth: 2 +--- +Language: Cpp +DeriveLineEnding: false +UseCRLF: true +DerivePointerAlignment: false +PointerAlignment: Left +AlignConsecutiveAssignments: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AlwaysBreakTemplateDeclarations: Yes +AccessModifierOffset: -2 +AlignTrailingComments: true +SpacesBeforeTrailingComments: 2 +NamespaceIndentation: Inner +MaxEmptyLinesToKeep: 1 +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: false + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: true +ColumnLimit: 88 +ForEachMacros: ['Q_FOREACH', 'foreach'] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f869712 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.cpp text eol=crlf +*.h text eol=crlf diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 0000000..8e5defa --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,16 @@ +name: Lint Github++ + +on: + push: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Check format + uses: ModOrganizer2/check-formatting-action@master + with: + check-path: "." diff --git a/include/githubpp/github.h b/include/githubpp/github.h index b8d5ffb..0085fd5 100644 --- a/include/githubpp/github.h +++ b/include/githubpp/github.h @@ -1,32 +1,28 @@ #pragma once -#include -#include +#include #include #include -#include -#include +#include +#include #include +#include #include class GitHubException : public std::exception { public: - GitHubException(const QJsonObject &errorObj) - : std::exception() + GitHubException(const QJsonObject& errorObj) : std::exception() { initMessage(errorObj); } virtual ~GitHubException() throw() override {} - virtual const char *what() const throw() - { - return m_Message.constData(); - } + virtual const char* what() const throw() { return m_Message.constData(); } private: - void initMessage(const QJsonObject &obj) + void initMessage(const QJsonObject& obj) { if (obj.contains("http_status")) { m_Message = QString("HTTP Status %1: %2") @@ -55,48 +51,51 @@ class GitHub : public QObject Q_OBJECT public: - enum class Method { GET, POST }; + enum class Method + { + GET, + POST + }; - struct Repository { - Repository(const QString &owner, const QString &project) - : owner(owner) - , project(project) - { - } + struct Repository + { + Repository(const QString& owner, const QString& project) + : owner(owner), project(project) + {} QString owner; QString project; }; public: - GitHub(const char *clientId = nullptr); + GitHub(const char* clientId = nullptr); ~GitHub(); - QJsonArray releases(const Repository &repo); - void releases(const Repository &repo, - const std::function &callback); + QJsonArray releases(const Repository& repo); + void releases(const Repository& repo, + const std::function& callback); private: - QJsonDocument request(Method method, const QString &path, - const QByteArray &data, bool relative); - void request(Method method, const QString &path, const QByteArray &data, - const std::function &callback, + QJsonDocument request(Method method, const QString& path, const QByteArray& data, + bool relative); + void request(Method method, const QString& path, const QByteArray& data, + const std::function& callback, bool relative); - QJsonDocument handleReply(QNetworkReply *reply); - QNetworkReply *genReply(Method method, const QString &path, - const QByteArray &data, bool relative); + QJsonDocument handleReply(QNetworkReply* reply); + QNetworkReply* genReply(Method method, const QString& path, const QByteArray& data, + bool relative); private: struct Request { Method method = Method::GET; QByteArray data; - std::function callback; - QTimer* timer = nullptr; + std::function callback; + QTimer* timer = nullptr; QNetworkReply* reply = nullptr; }; - QNetworkAccessManager *m_AccessManager; + QNetworkAccessManager* m_AccessManager; // remember the replies that are in flight and delete them in the destructor std::vector m_replies; diff --git a/src/github.cpp b/src/github.cpp index 6ecfee4..1c91cfa 100644 --- a/src/github.cpp +++ b/src/github.cpp @@ -1,17 +1,16 @@ -#include -#include -#include #include "github.h" +#include +#include +#include -#include #include +#include static const QString GITHUB_URL("https://api.github.com"); static const QString USER_AGENT("GitHubPP"); - -GitHub::GitHub(const char* clientId) - : m_AccessManager(new QNetworkAccessManager(this)) {} +GitHub::GitHub(const char* clientId) : m_AccessManager(new QNetworkAccessManager(this)) +{} GitHub::~GitHub() { @@ -23,43 +22,40 @@ GitHub::~GitHub() } } -QJsonArray GitHub::releases(const Repository &repo) +QJsonArray GitHub::releases(const Repository& repo) { - QJsonDocument result - = request(Method::GET, - QString("repos/%1/%2/releases").arg(repo.owner, repo.project), - QByteArray(), - true); + QJsonDocument result = request( + Method::GET, QString("repos/%1/%2/releases").arg(repo.owner, repo.project), + QByteArray(), true); return result.array(); } -void GitHub::releases(const Repository &repo, - const std::function &callback) +void GitHub::releases(const Repository& repo, + const std::function& callback) { - request(Method::GET, - QString("repos/%1/%2/releases").arg(repo.owner, repo.project), - QByteArray(), [callback](const QJsonDocument &result) { - callback(result.array()); - }, true); + request( + Method::GET, QString("repos/%1/%2/releases").arg(repo.owner, repo.project), + QByteArray(), + [callback](const QJsonDocument& result) { + callback(result.array()); + }, + true); } -QJsonDocument GitHub::handleReply(QNetworkReply *reply) +QJsonDocument GitHub::handleReply(QNetworkReply* reply) { - int statusCode - = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (statusCode != 200) { return QJsonDocument(QJsonObject( {{"http_status", statusCode}, {"redirection", - reply->attribute(QNetworkRequest::RedirectionTargetAttribute) - .toString()}, - {"reason", reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute) - .toString()}})); + reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString()}, + {"reason", + reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString()}})); } QByteArray data = reply->readAll(); - if (data.isNull() || data.isEmpty() - || (strcmp(data.constData(), "null") == 0)) { + if (data.isNull() || data.isEmpty() || (strcmp(data.constData(), "null") == 0)) { return QJsonDocument(); } @@ -67,15 +63,14 @@ QJsonDocument GitHub::handleReply(QNetworkReply *reply) QJsonDocument result = QJsonDocument::fromJson(data, &parseError); if (parseError.error != QJsonParseError::NoError) { - return QJsonDocument( - QJsonObject({{"parse_error", parseError.errorString()}})); + return QJsonDocument(QJsonObject({{"parse_error", parseError.errorString()}})); } return result; } -QNetworkReply *GitHub::genReply(Method method, const QString &path, - const QByteArray &data, bool relative) +QNetworkReply* GitHub::genReply(Method method, const QString& path, + const QByteArray& data, bool relative) { QNetworkRequest request(relative ? GITHUB_URL + "/" + path : path); @@ -83,21 +78,21 @@ QNetworkReply *GitHub::genReply(Method method, const QString &path, request.setRawHeader("Accept", "application/vnd.github.v3+json"); switch (method) { - case Method::GET: - return m_AccessManager->get(request); - case Method::POST: - return m_AccessManager->post(request, data); - default: - // this shouldn't be possible as all enum options are handled - throw std::runtime_error("invalid method"); + case Method::GET: + return m_AccessManager->get(request); + case Method::POST: + return m_AccessManager->post(request, data); + default: + // this shouldn't be possible as all enum options are handled + throw std::runtime_error("invalid method"); } } -QJsonDocument GitHub::request(Method method, const QString &path, - const QByteArray &data, bool relative) +QJsonDocument GitHub::request(Method method, const QString& path, + const QByteArray& data, bool relative) { QEventLoop wait; - QNetworkReply *reply = genReply(method, path, data, relative); + QNetworkReply* reply = genReply(method, path, data, relative); connect(reply, SIGNAL(finished), &wait, SLOT(quit())); wait.exec(); @@ -112,18 +107,18 @@ QJsonDocument GitHub::request(Method method, const QString &path, } } -void GitHub::request(Method method, const QString &path, const QByteArray &data, - const std::function &callback, +void GitHub::request(Method method, const QString& path, const QByteArray& data, + const std::function& callback, bool relative) { // make sure the timer is owned by this so it's deleted correctly and // doesn't fire after the GitHub object is destroyed; this happens when // restarting MO by switching instances, for example - QTimer *timer = new QTimer(this); + QTimer* timer = new QTimer(this); timer->setSingleShot(true); timer->setInterval(10000); - QNetworkReply *reply = genReply(method, path, data, relative); + QNetworkReply* reply = genReply(method, path, data, relative); // remember this reply so it can be deleted in the destructor if necessary m_replies.push_back(reply); @@ -131,15 +126,20 @@ void GitHub::request(Method method, const QString &path, const QByteArray &data, Request req = {method, data, callback, timer, reply}; // finished - connect(reply, &QNetworkReply::finished, [this, req]{ onFinished(req); }); + connect(reply, &QNetworkReply::finished, [this, req] { + onFinished(req); + }); // error - connect( - reply, qOverload(&QNetworkReply::errorOccurred), - [this, req](auto&& error){ onError(req, error); }); + connect(reply, qOverload(&QNetworkReply::errorOccurred), + [this, req](auto&& error) { + onError(req, error); + }); // timeout - connect(timer, &QTimer::timeout, [this, req]{ onTimeout(req); }); + connect(timer, &QTimer::timeout, [this, req] { + onTimeout(req); + }); timer->start(); } @@ -147,14 +147,13 @@ void GitHub::request(Method method, const QString &path, const QByteArray &data, void GitHub::onFinished(const Request& req) { QJsonDocument result = handleReply(req.reply); - QJsonObject object = result.object(); + QJsonObject object = result.object(); req.timer->stop(); if (object.value("http_status").toInt() == 301) { - request( - req.method, object.value("redirection").toString(), - req.data, req.callback, false); + request(req.method, object.value("redirection").toString(), req.data, req.callback, + false); } else { req.callback(result); } @@ -168,8 +167,8 @@ void GitHub::onError(const Request& req, QNetworkReply::NetworkError error) // already logs a message if (error != QNetworkReply::OperationCanceledError) { qCritical().noquote().nospace() - << "Github: request for " << req.reply->url().toString() << " failed, " - << req.reply->errorString() << " (" << error << ")"; + << "Github: request for " << req.reply->url().toString() << " failed, " + << req.reply->errorString() << " (" << error << ")"; } req.timer->stop(); @@ -186,7 +185,7 @@ void GitHub::onError(const Request& req, QNetworkReply::NetworkError error) void GitHub::onTimeout(const Request& req) { qCritical().noquote().nospace() - << "Github: request for " << req.reply->url().toString() << " timed out"; + << "Github: request for " << req.reply->url().toString() << " timed out"; // don't delete the reply, abort will fire the error() handler above req.reply->abort();