Compare commits
19 Commits
Author | SHA1 | Date |
---|---|---|
tastytea | f57f3b578d | |
tastytea | f5dc5e2359 | |
tastytea | e1c20bd1bd | |
tastytea | 9caeab9b91 | |
tastytea | aabd458e62 | |
tastytea | a1850db226 | |
tastytea | 7438f878c2 | |
tastytea | 6a4e15df81 | |
tastytea | 82261aadfb | |
tastytea | 23031b0dc9 | |
tastytea | f869ed9df2 | |
tastytea | 1e52e8edac | |
tastytea | 5cbbca2111 | |
tastytea | 6b08adce38 | |
tastytea | 98b6572b14 | |
tastytea | f3b97151f1 | |
tastytea | a83a11d8e2 | |
tastytea | c3fb4850ae | |
tastytea | 6dc9c1a740 |
|
@ -0,0 +1,131 @@
|
|||
# -*- mode: yaml -*-
|
||||
# Written for clang-format 10.
|
||||
# https://releases.llvm.org/10.0.0/tools/clang/docs/ClangFormatStyleOptions.html
|
||||
---
|
||||
DisableFormat: false
|
||||
Language: Cpp
|
||||
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
# AlignConsecutiveBitFields: false # clang-format 11
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignConsecutiveMacros: false
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignOperands: true # clang-format 11: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
# AllowShortEnumsOnASingleLine: false # clang-format 11
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping: # If BreakBeforeBraces is set to Custom.
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
# BeforeLambdaBody: true # clang-format 11
|
||||
# BeforeWhile: true # clang-format 11
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
# CommentPragmas: 'regex'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- FOREACH
|
||||
- RANGES_FOR
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories: # stdlib headers into own group.
|
||||
- Regex: '^[^\.]+$'
|
||||
Priority: 4
|
||||
# IndentCaseBlocks: false # clang-format 11
|
||||
IndentCaseLabels: false
|
||||
# IndentExternBlock: NoIndent # clang-format 11
|
||||
IndentGotoLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
# MacroBlockBegin: 'string'
|
||||
# MacroBlockEnd: 'string'
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
# NamespaceMacros: 'string'
|
||||
PenaltyBreakAssignment: 250
|
||||
PenaltyBreakBeforeFirstCallParameter: 300
|
||||
# PenaltyBreakComment: 300
|
||||
# PenaltyBreakFirstLessLess: 120
|
||||
# PenaltyBreakString: 1000
|
||||
# PenaltyBreakTemplateDeclaration: 10
|
||||
# PenaltyExcessCharacter: 1000000
|
||||
# PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
# RawStringFormats: # <YAML>
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
# StatementMacros:
|
||||
# - Q_UNUSED
|
||||
# - QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
# TypenameMacros:
|
||||
# - STACK_OF
|
||||
# - LIST
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
# WhitespaceSensitiveMacros: ['string', 'string'] # clang-format 11
|
||||
...
|
|
@ -0,0 +1,20 @@
|
|||
# Configuration file for EditorConfig.
|
||||
# More information is available under <https://editorconfig.org/>.
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 80
|
||||
|
||||
[*.?pp]
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
|
||||
[{CMakeLists.txt,*.cmake}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
|
@ -1,8 +1,8 @@
|
|||
# IMPORTED target CURL::libcurl needs 3.12.
|
||||
cmake_minimum_required(VERSION 3.12...3.17)
|
||||
cmake_minimum_required(VERSION 3.12...3.18)
|
||||
|
||||
project(gitea2rss
|
||||
VERSION 0.6.0
|
||||
VERSION 0.7.0
|
||||
DESCRIPTION "Generates RSS feeds from Gitea releases or tags."
|
||||
LANGUAGES CXX)
|
||||
|
||||
|
|
21
README.adoc
21
README.adoc
|
@ -1,6 +1,7 @@
|
|||
= gitea2rss
|
||||
|
||||
*gitea2rss* Generates RSS feeds from https://gitea.io[Gitea] releases or tags.
|
||||
*gitea2rss* Generates RSS feeds from https://gitea.io[Gitea] releases, tags and
|
||||
commits.
|
||||
|
||||
https://rss.schlomp.space/?repo=tastytea/gitea2rss[Subscribe to gitea2rss releases].
|
||||
|
||||
|
@ -11,17 +12,17 @@ For an example nginx configuration file, see https://schlomp.space/tastytea/gite
|
|||
|
||||
== Install
|
||||
|
||||
=== Gentoo
|
||||
[alt="Packaging status" link=https://repology.org/project/gitea2rss/versions]
|
||||
image::https://repology.org/badge/vertical-allrepos/gitea2rss.svg[]
|
||||
|
||||
Add my https://schlomp.space/tastytea/overlay[repository] and install it from
|
||||
there.
|
||||
=== Gentoo
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
eselect repository enable tastytea
|
||||
echo "www-misc/gitea2rss ~amd64" >> /etc/portage/package.accept_keywords/gitea2rss
|
||||
emaint sync -r tastytea
|
||||
emerge -a dev-util/gitea2rss
|
||||
eselect repository enable guru
|
||||
echo 'www-misc/gitea2rss' >> /etc/portage/package.accept_keywords/gitea2rss
|
||||
emaint sync -r guru
|
||||
emerge -a www-misc/gitea2rss
|
||||
----
|
||||
|
||||
=== From source
|
||||
|
@ -29,7 +30,7 @@ emerge -a dev-util/gitea2rss
|
|||
==== Dependencies
|
||||
|
||||
* Tested OS: Linux
|
||||
* C++ compiler (tested: https://gcc.gnu.org/[gcc] 8/9,
|
||||
* C++ compiler (tested: https://gcc.gnu.org/[gcc] 8/9/10,
|
||||
https://llvm.org/[clang] 7)
|
||||
* https://cmake.org/[cmake] (at least: 3.12)
|
||||
* https://curl.haxx.se/libcurl/[libcurl] (at least: 7.56)
|
||||
|
@ -70,7 +71,7 @@ cmake --build .
|
|||
.cmake options:
|
||||
* `-DCMAKE_BUILD_TYPE=Debug` for a debug build.
|
||||
* `-DWITH_MAN=NO` to not compile the manpage.
|
||||
* `WITH_TESTS=YES` to compile the tests.
|
||||
* `-DWITH_TESTS=YES` to compile the tests.
|
||||
|
||||
You can run the tests with `ctest` inside `build/tests`. Install with `make
|
||||
install`.
|
||||
|
|
|
@ -28,7 +28,7 @@ server {
|
|||
fastcgi_param GITEA2RSS_BASEURL "https://git.example.com";
|
||||
|
||||
fastcgi_cache gitea2rss;
|
||||
fastcgi_cache_valid 200 20m; # Cache answers for up to 20 minutes.
|
||||
fastcgi_cache_valid 200 10m; # Cache answers for up to 10 minutes.
|
||||
fastcgi_cache_lock on; # Relay only one identical request at a time.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
:doctype: manpage
|
||||
:Author: tastytea
|
||||
:Email: tastytea@tastytea.de
|
||||
:Date: 2020-10-27
|
||||
:Date: 2021-04-25
|
||||
:Revision: 0.0.0
|
||||
:man source: gitea2rss
|
||||
:man version: {revision}
|
||||
|
@ -14,7 +14,7 @@ gitea2rss - Generates RSS feeds from Gitea releases or tags.
|
|||
|
||||
== SYNOPSIS
|
||||
|
||||
*gitea2rss* _URL of Gitea project_ [_releases_|_tags_]
|
||||
*gitea2rss* _URL of Gitea project_ [_releases_|_tags_|_commits_]
|
||||
|
||||
== DESCRIPTION
|
||||
|
||||
|
@ -50,6 +50,9 @@ this in it:
|
|||
<link rel="alternate" type="application/rss+xml"
|
||||
title="Tags of {{.Repository.Name}}"
|
||||
href="https://rss.example.com/?repo={{.Repository.Owner.Name}}/{{.Repository.Name}}&type=tags"/>
|
||||
<link rel="alternate" type="application/rss+xml"
|
||||
title="Commits of {{.Repository.Name}}"
|
||||
href="https://rss.example.com/?repo={{.Repository.Owner.Name}}/{{.Repository.Name}}&type=commits"/>
|
||||
{{end}}
|
||||
----
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* This file is part of gitea2rss.
|
||||
* Copyright © 2021 tastytea <tastytea@tastytea.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gitea2rss.hpp"
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace gitea2rss
|
||||
{
|
||||
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::stringstream;
|
||||
|
||||
uint8_t write_commits(const string &url)
|
||||
{
|
||||
const string baseurl = get_baseurl(url);
|
||||
const string repo = get_repo(url);
|
||||
stringstream data(get_http(baseurl + "/api/v1/repos/" + repo + "/commits"));
|
||||
|
||||
if (cgi)
|
||||
{
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
if (data.str().empty())
|
||||
{
|
||||
cerr << "Error: Could not download commits.\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
write_preamble(url, "commits");
|
||||
|
||||
Json::Value json;
|
||||
data >> json;
|
||||
|
||||
for (const Json::Value &commit : json)
|
||||
{
|
||||
const string sha = commit["sha"].asString();
|
||||
string message = escape_some_html(
|
||||
commit["commit"]["message"].asString());
|
||||
const string title = message.substr(0, message.find('\n'));
|
||||
{
|
||||
size_t pos{};
|
||||
while ((pos = message.find('\n')) != string::npos)
|
||||
{
|
||||
message.replace(pos, 1, "<br>");
|
||||
}
|
||||
}
|
||||
const string commit_url = commit["html_url"].asString();
|
||||
const string author = commit["commit"]["author"]["email"].asString()
|
||||
+ " ("
|
||||
+ commit["commit"]["author"]["name"].asString()
|
||||
+ ")";
|
||||
const string date = strtime(
|
||||
commit["commit"]["author"]["date"].asString());
|
||||
|
||||
cout << " <item>\n";
|
||||
write_line(6, "title", get_project(url) + ": " + title);
|
||||
write_line(6, "link", commit_url);
|
||||
write_line(6, "guid isPermaLink=\"false\"",
|
||||
get_domain(url) + " commit " + sha);
|
||||
write_line(6, "author", author);
|
||||
write_line(6, "pubDate", date);
|
||||
write_line(6, "description",
|
||||
"\n <![CDATA[<p>" + message + "</p>]]>\n ");
|
||||
cout << " </item>\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace gitea2rss
|
|
@ -1,5 +1,5 @@
|
|||
/* This file is part of gitea2rss.
|
||||
* Copyright © 2019, 2020 tastytea <tastytea@tastytea.de>
|
||||
* Copyright © 2019-2021 tastytea <tastytea@tastytea.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -55,6 +55,9 @@ uint8_t write_releases(const string &url);
|
|||
//! Write tags.
|
||||
uint8_t write_tags(const string &url);
|
||||
|
||||
//! Write commits.
|
||||
uint8_t write_commits(const string &url);
|
||||
|
||||
//! @brief Get the base URL, without trailing slash.
|
||||
string get_baseurl(const string &url);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* This file is part of gitea2rss.
|
||||
* Copyright © 2019, 2020 tastytea <tastytea@tastytea.de>
|
||||
* Copyright © 2019-2021 tastytea <tastytea@tastytea.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "gitea2rss.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
@ -67,7 +68,7 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
cerr << "usage: " << argv[0]
|
||||
<< " URL of Gitea project [releases|tags]\n";
|
||||
<< " URL of Gitea project [releases|tags|commits]\n";
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
@ -90,6 +91,10 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
ret = write_tags(url);
|
||||
}
|
||||
else if (type == "commits")
|
||||
{
|
||||
ret = write_commits(url);
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* This file is part of gitea2rss.
|
||||
* Copyright © 2019, 2020 tastytea <tastytea@tastytea.de>
|
||||
* Copyright © 2019-2021 tastytea <tastytea@tastytea.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include "gitea2rss.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <regex>
|
||||
|
@ -50,8 +51,8 @@ string get_project(const string &url)
|
|||
|
||||
string escape_some_html(string html)
|
||||
{
|
||||
const std::map<const char, const string> names = {{'<', "<"},
|
||||
{'>', ">"}};
|
||||
const std::map<const char, const string> names = {{'<', "<"},
|
||||
{'>', ">"}};
|
||||
|
||||
for (const auto &pair : names)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* This file is part of gitea2rss.
|
||||
* Copyright © 2019, 2020 tastytea <tastytea@tastytea.de>
|
||||
* Copyright © 2019-2021 tastytea <tastytea@tastytea.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
|
||||
#include "gitea2rss.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace gitea2rss
|
||||
|
@ -45,7 +47,7 @@ uint8_t write_tags(const string &url)
|
|||
return 2;
|
||||
}
|
||||
|
||||
write_preamble(url, "releases");
|
||||
write_preamble(url, "tags");
|
||||
|
||||
Json::Value json;
|
||||
data >> json;
|
||||
|
|
24
src/time.cpp
24
src/time.cpp
|
@ -15,7 +15,10 @@
|
|||
*/
|
||||
|
||||
#include "gitea2rss.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
namespace gitea2rss
|
||||
{
|
||||
|
@ -32,11 +35,28 @@ string strtime(const system_clock::time_point &timepoint)
|
|||
|
||||
string strtime(const string &time)
|
||||
{
|
||||
// FIXME: Do this more elegantly.
|
||||
std::tm tm = {};
|
||||
tm.tm_isdst = -1; // Detect daylight saving time.
|
||||
std::stringstream ss(time);
|
||||
ss >> std::get_time(&tm, "%Y-%m-%dT%T"); // Assume time is UTC.
|
||||
return strtime(system_clock::from_time_t(timegm(&tm)));
|
||||
ss >> std::get_time(&tm, "%Y-%m-%dT%T");
|
||||
std::time_t time_tmp = timegm(&tm);
|
||||
|
||||
constexpr size_t zone_start = 19;
|
||||
if (time[zone_start] == '+')
|
||||
{
|
||||
string zone = time.substr(zone_start + 1);
|
||||
time_tmp -= std::stol(zone.substr(0, 2)) * 60 * 60;
|
||||
time_tmp -= std::stol(zone.substr(3)) * 60;
|
||||
}
|
||||
else if (time[zone_start] == '+')
|
||||
{
|
||||
string zone = time.substr(zone_start + 1);
|
||||
time_tmp += std::stol(zone.substr(0, 2)) * 60 * 60;
|
||||
time_tmp += std::stol(zone.substr(3)) * 60;
|
||||
}
|
||||
|
||||
return strtime(system_clock::from_time_t(time_tmp));
|
||||
}
|
||||
|
||||
} // namespace gitea2rss
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* This file is part of gitea2rss.
|
||||
* Copyright © 2019, 2020 tastytea <tastytea@tastytea.de>
|
||||
* Copyright © 2019-2021 tastytea <tastytea@tastytea.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -15,7 +15,9 @@
|
|||
*/
|
||||
|
||||
#include "gitea2rss.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
|
@ -30,7 +32,8 @@ SCENARIO("escape_some_html() works as expected", "[strings]")
|
|||
THEN("The HTML is escaped")
|
||||
{
|
||||
REQUIRE(escaped
|
||||
== "<p><small>.</small></p>");
|
||||
== "<p><small>.</"
|
||||
"small></p>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ SCENARIO("get_http() works as expected", "[http]")
|
|||
|
||||
THEN("Answer is not empty")
|
||||
{
|
||||
REQUIRE(answer != "");
|
||||
REQUIRE(!answer.empty());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ SCENARIO("get_http() works as expected", "[http]")
|
|||
|
||||
THEN("Answer is empty")
|
||||
{
|
||||
REQUIRE(answer == "");
|
||||
REQUIRE(answer.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue