Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
altlinux-packages-bot
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kirill Unitsaev
altlinux-packages-bot
Commits
a333db40
Project 'ximper/mkimage-profiles' was moved to 'ximperlinux/mkimage-profiles'. Please update any links and bookmarks that may still have the old path.
Verified
Commit
a333db40
authored
Mar 10, 2026
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
news: add /pulse command for repository statistics summary
parent
48947111
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
79 additions
and
3 deletions
+79
-3
methods.py
src/altrepo/parser/methods.py
+26
-0
urls.py
src/altrepo/parser/news/urls.py
+5
-2
help.py
src/handlers/help.py
+1
-0
news.py
src/handlers/news.py
+47
-1
No files found.
src/altrepo/parser/methods.py
View file @
a333db40
...
@@ -54,6 +54,32 @@ class NewsInfo:
...
@@ -54,6 +54,32 @@ class NewsInfo:
async
def
p10
(
self
)
->
models
.
PackagesModel
|
None
:
async
def
p10
(
self
)
->
models
.
PackagesModel
|
None
:
return
await
self
.
_get_packages
(
"p10"
)
return
await
self
.
_get_packages
(
"p10"
)
async
def
bugs_by_range
(
self
,
date_from
:
date
,
date_to
:
date
)
->
dict
[
str
,
int
]
|
None
:
urls
=
await
urls_for_range
(
self
.
client
,
date_from
,
date_to
,
"bugs"
)
if
not
urls
:
return
None
totals
=
{
"quickly_resolved"
:
0
,
"new"
:
0
,
"old"
:
0
,
"resolved"
:
0
,
"reopened"
:
0
,
"random"
:
0
,
}
for
_
,
url
in
urls
:
html
=
await
self
.
client
.
get
(
url
,
"koi8-r"
)
data
=
await
bugs_parser
(
html
,
url
)
if
data
and
isinstance
(
data
,
models
.
BugsModel
):
for
key
in
totals
:
items
=
getattr
(
data
,
key
,
None
)
if
items
:
totals
[
key
]
+=
len
(
items
)
if
all
(
v
==
0
for
v
in
totals
.
values
()):
return
None
return
totals
async
def
packages_by_range
(
async
def
packages_by_range
(
self
,
date_from
:
date
,
date_to
:
date
self
,
date_from
:
date
,
date_to
:
date
)
->
models
.
PackagesModel
|
None
:
)
->
models
.
PackagesModel
|
None
:
...
...
src/altrepo/parser/news/urls.py
View file @
a333db40
...
@@ -41,8 +41,11 @@ async def urls_parser(client):
...
@@ -41,8 +41,11 @@ async def urls_parser(client):
return
models
.
NewsURL
(
**
result
)
return
models
.
NewsURL
(
**
result
)
async
def
urls_for_range
(
client
,
date_from
:
date
,
date_to
:
date
)
->
list
[
tuple
[
date
,
str
]]:
async
def
urls_for_range
(
client
,
date_from
:
date
,
date_to
:
date
,
news_type
:
str
=
"packages"
)
->
list
[
tuple
[
date
,
str
]]:
results
=
[]
results
=
[]
pattern
=
re
.
compile
(
rf
"Sisyphus-(
\
d{{8}}) {re.escape(news_type)}"
)
current
=
date_from
.
replace
(
day
=
1
)
current
=
date_from
.
replace
(
day
=
1
)
while
current
<=
date_to
:
while
current
<=
date_to
:
...
@@ -61,7 +64,7 @@ async def urls_for_range(client, date_from: date, date_to: date) -> list[tuple[d
...
@@ -61,7 +64,7 @@ async def urls_for_range(client, date_from: date, date_to: date) -> list[tuple[d
if
not
a
or
not
a
.
get
(
"href"
):
if
not
a
or
not
a
.
get
(
"href"
):
continue
continue
text
=
a
.
get_text
(
strip
=
True
)
text
=
a
.
get_text
(
strip
=
True
)
match
=
re
.
search
(
r"Sisyphus-(\d{8}) packages"
,
text
)
match
=
pattern
.
search
(
text
)
if
match
:
if
match
:
news_date
=
datetime
.
strptime
(
match
.
group
(
1
),
"
%
Y
%
m
%
d"
)
.
date
()
news_date
=
datetime
.
strptime
(
match
.
group
(
1
),
"
%
Y
%
m
%
d"
)
.
date
()
if
date_from
<=
news_date
<=
date_to
:
if
date_from
<=
news_date
<=
date_to
:
...
...
src/handlers/help.py
View file @
a333db40
...
@@ -76,5 +76,6 @@ async def help_handler(m: Message) -> None:
...
@@ -76,5 +76,6 @@ async def help_handler(m: Message) -> None:
" /statistics [branch] — статистика репозитория
\n
"
" /statistics [branch] — статистика репозитория
\n
"
" /news — меню новостей
\n
"
" /news — меню новостей
\n
"
" /news_range дата_от дата_до — новости за период
\n
"
" /news_range дата_от дата_до — новости за период
\n
"
" /pulse [дней] — пульс Сизифа (по умолчанию 7)
\n
"
)
)
src/handlers/news.py
View file @
a333db40
import
asyncio
from
telegrinder
import
Dispatch
,
Message
,
CallbackQuery
from
telegrinder
import
Dispatch
,
Message
,
CallbackQuery
from
telegrinder.rules
import
Command
,
Argument
,
CallbackDataMarkup
,
Text
,
IsPrivate
from
telegrinder.rules
import
Command
,
Argument
,
CallbackDataMarkup
,
Text
,
IsPrivate
from
datetime
import
datetime
from
datetime
import
datetime
,
timedelta
from
altrepo
import
altrepo
from
altrepo
import
altrepo
from
services.news
import
format_packages
,
format_bugs
from
services.news
import
format_packages
,
format_bugs
from
services.utils
import
_bold
,
int_validator
from
data.keyboards
import
news_keyboards
from
data.keyboards
import
news_keyboards
dp
=
Dispatch
()
dp
=
Dispatch
()
...
@@ -164,3 +167,46 @@ async def news_range_handler(
...
@@ -164,3 +167,46 @@ async def news_range_handler(
for
msg
in
updated
:
for
msg
in
updated
:
await
m
.
ctx_api
.
send_message
(
chat_id
=
chat_id
,
text
=
msg
)
await
m
.
ctx_api
.
send_message
(
chat_id
=
chat_id
,
text
=
msg
)
await
m
.
ctx_api
.
send_message
(
chat_id
=
chat_id
,
text
=
info_message
)
await
m
.
ctx_api
.
send_message
(
chat_id
=
chat_id
,
text
=
info_message
)
@dp.message
(
Command
(
"pulse"
,
Argument
(
"days"
,
[
int_validator
],
optional
=
True
))
)
async
def
pulse_handler
(
m
:
Message
,
days
:
int
|
None
=
None
)
->
None
:
days
=
days
or
7
if
days
<
1
or
days
>
180
:
await
m
.
answer
(
"Допустимый диапазон: 1–180 дней."
)
return
d_to
=
datetime
.
now
()
.
date
()
d_from
=
d_to
-
timedelta
(
days
=
days
-
1
)
await
m
.
answer
(
f
"Сбор статистики за {days} дн..."
)
packages_data
,
bugs_data
=
await
asyncio
.
gather
(
altrepo
.
parser
.
news
.
packages_by_range
(
d_from
,
d_to
),
altrepo
.
parser
.
news
.
bugs_by_range
(
d_from
,
d_to
),
)
added
=
len
(
packages_data
.
added
)
if
packages_data
and
packages_data
.
added
else
0
updated
=
len
(
packages_data
.
updated
)
if
packages_data
and
packages_data
.
updated
else
0
removed
=
len
(
packages_data
.
removed
)
if
packages_data
and
packages_data
.
removed
else
0
message
=
_bold
(
"Пульс Сизифа
\n\n
"
)
message
+=
"🛍 Пакеты:
\n
"
message
+=
f
" Добавлено новых: {added}
\n
"
message
+=
f
" Обновлено: {updated}
\n
"
message
+=
f
" Удалено: {removed}
\n\n
"
if
bugs_data
:
message
+=
"🪲 Баги:
\n
"
message
+=
f
" Новые: {bugs_data['new']}
\n
"
message
+=
f
" Переоткрытые: {bugs_data['reopened']}
\n
"
message
+=
f
" Быстро закрытые: {bugs_data['quickly_resolved']}
\n
"
message
+=
f
" Закрытые: {bugs_data['resolved']}
\n\n
"
date_range
=
f
"{d_from.strftime('
%
d.
%
m.
%
Y')} — {d_to.strftime('
%
d.
%
m.
%
Y')}"
message
+=
f
"* статистика за {date_range}"
await
m
.
answer
(
message
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment