Compare commits

...

19 Commits

Author SHA1 Message Date
tastytea f57f3b578d
Fix typo in cmake options.
continuous-integration/drone/push Build is passing Details
2021-05-20 01:11:29 +02:00
tastytea f5dc5e2359
Update installation instructions for Gentoo. 2021-05-18 00:12:14 +02:00
tastytea e1c20bd1bd
Add repology badge. 2021-05-17 23:56:25 +02:00
tastytea 9caeab9b91
Add “commits” to usage info in manpage.
continuous-integration/drone/push Build is passing Details
2021-04-25 10:50:13 +02:00
tastytea aabd458e62
Version bump 0.7.0.
continuous-integration/drone/push Build is passing Details
2021-04-25 10:41:02 +02:00
tastytea a1850db226
Fix test for escape_some_html().
continuous-integration/drone/push Build is passing Details
2021-04-21 12:49:32 +02:00
tastytea 7438f878c2
Use hexadecimal instead of named HTML entities in replacements.
continuous-integration/drone/push Build is failing Details
See <https://www.rssboard.org/rss-profile#data-types-characterdata>.
2021-04-21 12:42:26 +02:00
tastytea 6a4e15df81
Cache only up to 10 minutes in nginx example.
continuous-integration/drone/push Build is passing Details
2021-04-21 12:34:37 +02:00
tastytea 82261aadfb
Escape some HTML in commit message.
continuous-integration/drone/push Build is passing Details
2021-04-21 12:31:04 +02:00
tastytea 23031b0dc9
commits: Replace newlines in commit message with <br>.
continuous-integration/drone/push Build is passing Details
2021-04-21 12:14:26 +02:00
tastytea f869ed9df2
Fix time conversion.
continuous-integration/drone/push Build is passing Details
2021-04-21 12:05:36 +02:00
tastytea 1e52e8edac
Add date to commit items. 2021-04-21 12:05:14 +02:00
tastytea 5cbbca2111
Add documentation for commits. 2021-04-21 11:13:20 +02:00
tastytea 6b08adce38
Add support for commits.
continuous-integration/drone/push Build is passing Details
Bug: #2
2021-04-21 11:03:39 +02:00
tastytea 98b6572b14
Don't call tags releases in RSS output. 2021-04-21 10:32:15 +02:00
tastytea f3b97151f1
Update .clang-format.. 2020-10-30 22:04:01 +01:00
tastytea a83a11d8e2
Add .editorconfig.
continuous-integration/drone/push Build is passing Details
2020-10-27 12:41:08 +01:00
tastytea c3fb4850ae
Add .clang-format. 2020-10-27 12:39:27 +01:00
tastytea 6dc9c1a740
Fix warning in test. 2020-10-27 12:38:14 +01:00
14 changed files with 309 additions and 30 deletions

131
.clang-format Normal file
View File

@ -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
...

20
.editorconfig Normal file
View File

@ -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

View File

@ -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)

View File

@ -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`.

View File

@ -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.
}
}

View File

@ -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}}&amp;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}}&amp;type=commits"/>
{{end}}
----

90
src/commits.cpp Normal file
View File

@ -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

View File

@ -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);

View File

@ -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)
{

View File

@ -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 = {{'<', "&lt;"},
{'>', "&gt;"}};
const std::map<const char, const string> names = {{'<', "&#x3C;"},
{'>', "&#x3E;"}};
for (const auto &pair : names)
{

View File

@ -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;

View File

@ -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

View File

@ -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
== "&lt;p&gt;&lt;small&gt;.&lt;/small&gt;&lt;/p&gt;");
== "&#x3C;p&#x3E;&#x3C;small&#x3E;.&#x3C;/"
"small&#x3E;&#x3C;/p&#x3E;");
}
}
}

View File

@ -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());
}
}
}