Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
ae802d0
build(deps-dev): bump mkdocs-material from 9.6.14 to 9.6.15
dependabot[bot] Jul 1, 2025
3870375
build(deps-dev): bump pytest-xdist from 3.7.0 to 3.8.0
dependabot[bot] Jul 1, 2025
6547f71
Merge pull request #173 from swimmwatch/dependabot/pip/dev/mkdocs-mat…
swimmwatch Jul 2, 2025
a8811fc
Merge pull request #174 from swimmwatch/dependabot/pip/dev/pytest-xdi…
swimmwatch Jul 2, 2025
15a6cf3
build(deps): bump cryptography from 45.0.4 to 45.0.5
dependabot[bot] Jul 2, 2025
071e20d
Merge pull request #175 from swimmwatch/dependabot/pip/dev/cryptograp…
swimmwatch Jul 3, 2025
71a6539
build(deps-dev): bump typing-extensions from 4.14.0 to 4.14.1
dependabot[bot] Jul 4, 2025
d7436e2
Merge pull request #176 from swimmwatch/dependabot/pip/dev/typing-ext…
swimmwatch Jul 5, 2025
1353e11
build(deps-dev): bump freezegun from 1.5.2 to 1.5.3
dependabot[bot] Jul 15, 2025
60c8f1a
build(deps-dev): bump mypy from 1.16.1 to 1.17.0
dependabot[bot] Jul 15, 2025
c439fcc
Merge pull request #178 from swimmwatch/dependabot/pip/dev/mypy-1.17.0
swimmwatch Jul 15, 2025
bb35d3b
Merge pull request #177 from swimmwatch/dependabot/pip/dev/freezegun-…
swimmwatch Jul 15, 2025
ed6f089
build(deps-dev): bump mkdocstrings from 0.29.1 to 0.30.0
dependabot[bot] Jul 23, 2025
6e65d18
Merge pull request #179 from swimmwatch/dependabot/pip/dev/mkdocstrin…
swimmwatch Jul 24, 2025
dda6e72
build(deps-dev): bump mkdocs-material from 9.6.15 to 9.6.16
dependabot[bot] Jul 29, 2025
5ca5cce
Merge pull request #180 from swimmwatch/dependabot/pip/dev/mkdocs-mat…
swimmwatch Jul 29, 2025
2612ea9
feat: init check-update workflow
swimmwatch Jul 29, 2025
916f93f
feat: update check-update workflow title
swimmwatch Jul 29, 2025
e0184aa
feat: add test trigger workflow
swimmwatch Jul 29, 2025
29cfd4c
feat: use python version of webchanges utility
swimmwatch Jul 29, 2025
5639ddb
feat: use standard method for post request
swimmwatch Jul 29, 2025
9a8d466
fix: use single quote for yaml input config
swimmwatch Jul 29, 2025
9400575
feat: use GitHub token
swimmwatch Jul 29, 2025
b31b756
feat: use repo name
swimmwatch Jul 29, 2025
da9b936
fix: fix json passing to post request
swimmwatch Jul 29, 2025
bb0992a
feat: add between lines filter
swimmwatch Jul 30, 2025
b164e8c
feat: format diff content
swimmwatch Jul 30, 2025
1da04f3
feat: update poetry lock
swimmwatch Jul 30, 2025
9fbbc94
feat: add comments
swimmwatch Jul 30, 2025
19e5346
feat: add filters
swimmwatch Jul 30, 2025
aa2d257
feat: use bearer token
swimmwatch Jul 30, 2025
0d306a5
feat: update permissions
swimmwatch Jul 30, 2025
6478697
fix: resolve linters issues
swimmwatch Jul 30, 2025
e270383
fix: cache snapshots db
swimmwatch Jul 30, 2025
1f1f762
fix: change key name
swimmwatch Jul 30, 2025
29ae4a4
fix: fix run command
swimmwatch Jul 30, 2025
e4fff68
fix: test files
swimmwatch Jul 30, 2025
a85c27f
fix: debug step
swimmwatch Jul 30, 2025
bc7c03b
refactor: cache and restore snapshot db separately
swimmwatch Jul 30, 2025
2ad9d1e
fix: save missing config files
swimmwatch Jul 30, 2025
9b4dc3f
feat: try to use cat instead echo
swimmwatch Jul 30, 2025
187f05c
build(deps-dev): bump freezegun from 1.5.3 to 1.5.4
dependabot[bot] Jul 30, 2025
64eb4ff
Merge pull request #193 from swimmwatch/dependabot/pip/dev/freezegun-…
swimmwatch Jul 31, 2025
e3e466d
fix: make config hash key idempotency
swimmwatch Jul 31, 2025
307622b
fix: make config hash key idempotency (another try)_
swimmwatch Jul 31, 2025
56b2d22
feat: reformat files
swimmwatch Jul 31, 2025
fe67285
fix: change yc command
swimmwatch Jul 31, 2025
8a61832
feat: update format text method
swimmwatch Jul 31, 2025
269c990
feat: trigger workflow by schedule
swimmwatch Jul 31, 2025
1d3709a
feat: change cache key - remove config hash
swimmwatch Jul 31, 2025
9cfba2c
feat: add several parameters for github issue reporter (assignees, ty…
swimmwatch Jul 31, 2025
e04d18a
feat: add several parameters for github issue reporter (assignees, ty…
swimmwatch Jul 31, 2025
528ca03
feat: revert format content
swimmwatch Jul 31, 2025
465be87
feat: update action author
swimmwatch Jul 31, 2025
f81cfb0
build(deps-dev): bump mypy from 1.17.0 to 1.17.1
dependabot[bot] Jul 31, 2025
5f7ef97
Merge pull request #199 from swimmwatch/dependabot/pip/dev/mypy-1.17.1
swimmwatch Aug 1, 2025
05cff9e
feat: use diff format
swimmwatch Aug 2, 2025
27dc362
feat: update title job
swimmwatch Aug 2, 2025
dbe3548
feat: reformat code
swimmwatch Aug 2, 2025
510b540
feat: specify python and webchanges version
swimmwatch Aug 2, 2025
284d038
feat: update report title
swimmwatch Aug 2, 2025
82b53f4
feat: use single quotes for echo
swimmwatch Aug 2, 2025
0030567
feat: use double quotes for echo
swimmwatch Aug 2, 2025
c5815b3
fix: resolve syntax issue in config string
swimmwatch Aug 2, 2025
6dbbf19
feat: remove double quotes from job config
swimmwatch Aug 2, 2025
76d2733
feat: revert double quotes from job config
swimmwatch Aug 2, 2025
0fc758e
feat: use schedule trigger
swimmwatch Aug 2, 2025
f75a52b
fix: update hooks module docstring
swimmwatch Aug 3, 2025
f3ada02
feat: trim content length
swimmwatch Aug 4, 2025
23be5e1
feat: update docs per hour
swimmwatch Aug 4, 2025
0f6d0bf
Merge pull request #182 from swimmwatch/feature/181
swimmwatch Aug 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/actions/webchanges/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: "Web changes detector"
author: "Dmitry Vasiliev"
description: "Detect changes in web pages and notify via GitHub Actions"
branding:
icon: "check-circle"
color: "blue"

inputs:
config:
description: "Configuration for the web changes detector"
required: true
jobs:
description: "List of jobs to run for web changes detection"
required: true

runs:
using: "composite"
steps:
- name: "Set up environment"
shell: bash
run: |
echo "CONFIG_PATH=${{ github.workspace }}/config.yaml" >> $GITHUB_ENV
echo "JOBS_PATH=${{ github.workspace }}/jobs.yaml" >> $GITHUB_ENV
echo "SNAPSHOTS_DB=${{ github.workspace }}/snapshots.db" >> $GITHUB_ENV
echo "HOOKS_PATH=${{ github.action_path }}/hooks.py" >> $GITHUB_ENV
echo "WEBCHANGES_VERSION=3.30.0" >> $GITHUB_ENV
echo "PYTHON_VERSION=3.10" >> $GITHUB_ENV
- name: "Write configs to files"
shell: bash
run: |
echo '${{ inputs.config }}' > $CONFIG_PATH
echo '${{ inputs.jobs }}' > $JOBS_PATH
- name: "Setup Python"
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: "pip"
- name: "Install webchanges package"
shell: bash
run: |
pip install webchanges==${{ env.WEBCHANGES_VERSION }}
- name: "Compute SHA-256 of configs input"
shell: bash
run: |
# Compute the hash of the configs input and store it in an environment variable
JOB_HASH=$(sha256sum ${{ env.JOBS_PATH }} | awk '{ print $1 }')

# Compute cache key based on the hashes
echo "CACHE_KEY=${{ runner.os }}-snapshots-${JOB_HASH}" >> $GITHUB_ENV
- name: "Restore cache snapshots database"
id: cache-db
uses: actions/cache/restore@v4
with:
path: "${{ env.SNAPSHOTS_DB }}"
key: "${{ env.CACHE_KEY }}"
- name: "Check if snapshots database exists"
shell: bash
run: |
if [ ! -f $SNAPSHOTS_DB ]; then
echo "No snapshots database found, creating a new one."
else
echo "Snapshots database found, using existing one."
fi
- name: "Run web changes detection"
shell: bash
run: |
webchanges --config ${{ env.CONFIG_PATH }} --jobs ${{ env.JOBS_PATH }} --hooks ${{ env.HOOKS_PATH }} --database ${{ env.SNAPSHOTS_DB }}
- name: "Cache snapshots database"
uses: actions/cache/save@v4
with:
path: "${{ env.SNAPSHOTS_DB }}"
key: "${{ env.CACHE_KEY }}"
163 changes: 163 additions & 0 deletions .github/actions/webchanges/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
"""Custom reporters and filters for webchanges utility."""

import json
import logging
import re
import typing
from datetime import datetime
from datetime import timezone
from http import HTTPStatus
from typing import TypedDict

from webchanges.filters import FilterBase
from webchanges.reporters import MarkdownReporter

logger = logging.getLogger(__name__)


class GitHubIssueReporter(MarkdownReporter):
"""Reporter that submits reports as issues to a GitHub repository."""

__kind__ = "github_issue"

config: TypedDict(
"_ConfigReportGithubIssue",
{
"enabled": bool,
"token": str,
"owner": str,
"repo": str,
"title": typing.Optional[str],
"labels": list[str],
"format_dt": typing.Optional[str],
"format_content": typing.Optional[str],
"assignees": typing.Optional[typing.Sequence[str]],
"type": typing.Optional[str],
"milestone": typing.Optional[str],
},
)

_API_URL = "https://api.github.com/repos/{owner}/{repo}/issues"
_CONTENT_LIMIT = 65536 # GitHub issue body limit

def _format_title(self) -> str:
"""Format the title of the issue."""
now = datetime.now(tz=timezone.utc)
format_dt = self.config.get("format_dt", "%Y-%m-%d %H:%M:%S")

title = self.config.get("title")
if not title:
title = "WebChanges report"
else:
dt = now.strftime(format_dt)
title = title.format(dt=dt)

return title

def _format_text(self, content: str) -> str:
"""Format the content of the issue."""
format_content = self.config.get("format_content")
content = content[: self._CONTENT_LIMIT]
if format_content:
placeholder = "{content}"
max_content_length = self._CONTENT_LIMIT - (len(format_content) - len(placeholder))
content = content[:max_content_length]
content = format_content.format(content=content)

return content

def _create_issue(self, content: str):
"""Create an issue on GitHub."""
url = self._API_URL.format(owner=self.config["owner"], repo=self.config["repo"])
headers = {"Authorization": f"Bearer {self.config['token']}", "Accept": "application/json"}

title = self._format_title()
content = self._format_text(content)
issue_data = {"title": title, "body": content, "labels": self.config.get("labels", [])}

assignees = self.config.get("assignees", [])
if assignees:
issue_data["assignees"] = assignees

type_ = self.config.get("type")
if type_:
issue_data["type"] = type_

milestone = self.config.get("milestone")
if milestone:
issue_data["milestone"] = milestone

response = self.post_client(url, headers=headers, json=issue_data)

if response.status_code == HTTPStatus.CREATED:
logger.info("Issue created successfully.")
else:
json_object = json.loads(response.text)
json_formatted_str = json.dumps(json_object, indent=2)
raise RuntimeError(f"Failed to create issue: {json_formatted_str}")

def submit(
self,
max_length: int | None = None,
**kwargs: typing.Any,
) -> typing.Iterator[str]:
"""Submit the report to GitHub as an issue."""
lines = super().submit(max_length, **kwargs)
content = "\n".join(lines)
if not content:
logger.info("No content to submit.")
return

logger.info("Submitting issue to GitHub...")
self._create_issue(content)

return lines


def get_lines_between(
lines: typing.Sequence[str],
start_pattern: str | None = None,
end_pattern: str | None = None,
) -> typing.Generator[str, None, None]:
"""Yield lines between start and end patterns."""
started = False
for line in lines:
if not started:
if start_pattern and re.search(start_pattern, line):
started = True
continue
if end_pattern and re.search(end_pattern, line):
break

yield line


class BetweenLinesFilter(FilterBase):
"""Filter to extract lines between two patterns."""

__kind__ = "between"

__supported_subfilters__ = {
"start": "Pattern to match the start line.",
"end": "Pattern to match the end line.",
}

__default_subfilter__ = "indent"

@staticmethod
def filter(
data: str | bytes,
mime_type: str,
subfilter: dict[str, typing.Any],
) -> tuple[str | bytes, str]:
"""Filter lines between start and end patterns."""
start_pattern = subfilter.get("start")
end_pattern = subfilter.get("end")

lines = data.splitlines(keepends=True)
filtered_lines = get_lines_between(lines, start_pattern, end_pattern)

return (
"\n".join(filtered_lines),
mime_type,
)
42 changes: 42 additions & 0 deletions .github/workflows/check-update.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: "Check Telegram Mini App documentation updates"
on:
workflow_dispatch:
schedule:
- cron: '0 * * * *'

permissions:
issues: write

jobs:
check-telegram-docs-updates:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Telegram Mini App documentation updates
uses: ./.github/actions/webchanges
with:
jobs: |
name: Telegram Mini App documentation
url: https://core.telegram.org/bots/webapps
use_browser: false
filters:
- html2text
- between:
start: "#### __WebAppInitData"
end: "#### __Events Available for Mini Apps"
config: |
report:
tz: UTC
github_issue:
enabled: true
owner: "${{ github.repository_owner }}"
repo: "${{ github.event.repository.name }}"
token: "${{ secrets.GITHUB_TOKEN }}"
format_dt: "%Y-%m-%d"
title: "Telegram Mini App documentation update: {dt}"
assignees:
- "swimmwatch"
format_content: |
```diff
{content}
```
Loading
Loading