Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package urlwatch for openSUSE:Factory 
checked in at 2021-12-13 20:45:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/urlwatch (Old)
 and      /work/SRC/openSUSE:Factory/.urlwatch.new.2520 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "urlwatch"

Mon Dec 13 20:45:15 2021 rev:22 rq:940291 version:2.24

Changes:
--------
--- /work/SRC/openSUSE:Factory/urlwatch/urlwatch.changes        2021-04-14 
10:11:45.585572782 +0200
+++ /work/SRC/openSUSE:Factory/.urlwatch.new.2520/urlwatch.changes      
2021-12-13 20:51:34.076679890 +0100
@@ -1,0 +2,22 @@
+Mon Dec 13 16:06:55 UTC 2021 - Michael Vetter <[email protected]>
+
+- Update to 2.24:
+  Added:
+  * The Telegram reporter has gained two new options:
+    silent: Receive message notification without sound
+    monospace: Format message in monospace style
+  * Support for running a subset of jobs by specifying their index
+    on the command line
+  Changed:
+  * Migrated CI pipeline from Travis CI to Github Actions
+  * user_visible_url can now be specified for all job types (#654)
+  * Added a remove-duplicate-lines filter.
+  * Added a csv2text filter.
+  * Set envelope from (-f option) when sending emails using sendmail
+  * It is now possible to override the HTTP method when data is set
+    on a URL job
+  Fixed:
+  * Fix UnboundLocalError when SMTP auth is enabled, but keyring
+    is not installed (#667)
+
+-------------------------------------------------------------------

Old:
----
  urlwatch-2.23.tar.gz

New:
----
  urlwatch-2.24.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ urlwatch.spec ++++++
--- /var/tmp/diff_new_pack.Wyz0n8/_old  2021-12-13 20:51:34.560680200 +0100
+++ /var/tmp/diff_new_pack.Wyz0n8/_new  2021-12-13 20:51:34.564680202 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           urlwatch
-Version:        2.23
+Version:        2.24
 Release:        0
 Summary:        A tool for monitoring webpages for updates
 License:        BSD-3-Clause

++++++ urlwatch-2.23.tar.gz -> urlwatch-2.24.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/.github/workflows/unit-tests.yml 
new/urlwatch-2.24/.github/workflows/unit-tests.yml
--- old/urlwatch-2.23/.github/workflows/unit-tests.yml  1970-01-01 
01:00:00.000000000 +0100
+++ new/urlwatch-2.24/.github/workflows/unit-tests.yml  2021-11-07 
09:34:54.000000000 +0100
@@ -0,0 +1,37 @@
+name: Unit Tests
+
+on:
+  push:
+    branches:
+      - master
+  pull_request:
+    branches:
+      - master
+
+jobs:
+  build:
+    name: Python
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        python-version:
+          - 3.6
+          - 3.7
+          - 3.8
+          - 3.9
+    steps:
+    - uses: actions/checkout@v2
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        python -m pip install --requirement requirements.txt
+        python -m pip install pycodestyle==2.6.0 pytest
+        sudo apt install -y build-essential libpoppler-cpp-dev pkg-config 
python-dev tesseract-ocr
+        python -m pip install pdftotext docutils pygments pytesseract pillow jq
+    - name: Test with pytest
+      run: pytest -v
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/.travis.yml 
new/urlwatch-2.24/.travis.yml
--- old/urlwatch-2.23/.travis.yml       2021-04-10 10:48:22.000000000 +0200
+++ new/urlwatch-2.24/.travis.yml       1970-01-01 01:00:00.000000000 +0100
@@ -1,12 +0,0 @@
-language: python
-cache: pip
-python:
-  - "3.6"
-  - "3.7"
-  - "3.8"
-install:
-  - pip install -r requirements.txt
-  - pip install pycodestyle==2.6.0 pytest
-  - sudo apt-get install -y build-essential libpoppler-cpp-dev pkg-config 
python-dev tesseract-ocr
-  - pip install pdftotext docutils pygments pytesseract pillow jq
-script: pytest -v
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/CHANGELOG.md 
new/urlwatch-2.24/CHANGELOG.md
--- old/urlwatch-2.23/CHANGELOG.md      2021-04-10 10:48:22.000000000 +0200
+++ new/urlwatch-2.24/CHANGELOG.md      2021-11-07 09:34:54.000000000 +0100
@@ -4,6 +4,28 @@
 
 The format mostly follows [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/).
 
+## [2.24] -- 2021-11-07
+
+### Added
+
+- The Telegram reporter has gained two new options:
+  - `silent`: Receive message notification without sound
+  - `monospace`: Format message in monospace style
+- Support for running a subset of jobs by specifying their index on the 
command line
+
+### Changed
+
+- Migrated CI pipeline from Travis CI to Github Actions
+- `user_visible_url` can now be specified for all job types (#654, by 
kongomongo)
+- Added a `remove-duplicate-lines` filter. 
+- Added a `csv2text` filter.
+- Set envelope from (`-f` option) when sending emails using `sendmail`
+- It is now possible to override the HTTP `method` when `data` is set on a URL 
job
+
+### Fixed
+
+- Fix UnboundLocalError when SMTP auth is enabled, but keyring is not 
installed (#667)
+
 ## [2.23] -- 2021-04-10
 
 ### Added
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/README.md new/urlwatch-2.24/README.md
--- old/urlwatch-2.23/README.md 2021-04-10 10:48:22.000000000 +0200
+++ new/urlwatch-2.24/README.md 2021-11-07 09:34:54.000000000 +0100
@@ -1,4 +1,4 @@
-[![Build 
Status](https://travis-ci.org/thp/urlwatch.svg)](https://travis-ci.org/thp/urlwatch)
+[![Unit 
Tests](https://github.com/thp/urlwatch/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/thp/urlwatch/actions/workflows/unit-tests.yml)
 [![Packaging 
status](https://repology.org/badge/tiny-repos/urlwatch.svg)](https://repology.org/metapackage/urlwatch/versions)
 [![PyPI 
version](https://badge.fury.io/py/urlwatch.svg)](https://badge.fury.io/py/urlwatch)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/docs/source/advanced.rst 
new/urlwatch-2.24/docs/source/advanced.rst
--- old/urlwatch-2.23/docs/source/advanced.rst  2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/docs/source/advanced.rst  2021-11-07 09:34:54.000000000 
+0100
@@ -312,3 +312,49 @@
     filter:
       - grep: "Thing B"
 
+
+Running a subset of jobs
+------------------------
+
+To run one or more specific jobs instead of all known jobs, provide
+the job index numbers to the urlwatch command. For example, to run
+jobs with index 2, 4, and 7:
+
+.. code-block:: bash
+
+   urlwatch 2 4 7
+
+
+Sending HTML form data using POST
+---------------------------------
+
+To simulate submitting a HTML form using the POST method, you can pass
+the form fields in the ``data`` field of the job description:
+
+.. code-block:: yaml
+
+    name: "My POST Job"
+    url: http://example.com/foo
+    data:
+      username: "foo"
+      password: "bar"
+      submit: "Send query"
+
+By default, the request will use the HTTP ``POST`` method, and the
+``Content-type`` will be set to ``application/x-www-form-urlencoded``.
+
+
+Sending arbitrary data using HTTP PUT
+-------------------------------------
+
+It is possible to customize the HTTP method and ``Content-type`` header,
+allowing you to send arbitrary requests to the server:
+
+.. code-block:: yaml
+
+    name: "My PUT Request"
+    url: http://example.com/item/new
+    method: PUT
+    headers:
+      Content-type: application/json
+    data: '{"foo": true}'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/docs/source/conf.py 
new/urlwatch-2.24/docs/source/conf.py
--- old/urlwatch-2.23/docs/source/conf.py       2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/docs/source/conf.py       2021-11-07 09:34:54.000000000 
+0100
@@ -22,7 +22,7 @@
 author = 'Thomas Perl'
 
 # The full version, including alpha/beta/rc tags
-release = '2.23'
+release = '2.24'
 
 
 # -- General configuration ---------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/docs/source/filters.rst 
new/urlwatch-2.24/docs/source/filters.rst
--- old/urlwatch-2.23/docs/source/filters.rst   2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/docs/source/filters.rst   2021-11-07 09:34:54.000000000 
+0100
@@ -69,6 +69,7 @@
 - **sha1sum**: Calculate the SHA-1 checksum of the content
 - **shellpipe**: Filter using a shell command
 - **sort**: Sort input items
+- **remove-duplicate-lines**: Remove duplicate lines (case sensitive)
 - **strip**: Strip leading and trailing whitespace
 - **xpath**: Filter XML/HTML using XPath expressions
 - **jq**: Filter, transform and extract values from JSON
@@ -135,9 +136,7 @@
 
 To filter based on an
 `XPath <https://www.w3.org/TR/1999/REC-xpath-19991116/>`__ expression,
-you can use the ``xpath`` filter like so (see Microsoft???s `XPath
-Examples <https://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx>`__
-page for some other examples):
+you can use the ``xpath`` filter like so:
 
 .. code:: yaml
 
@@ -149,6 +148,9 @@
 element, which in turn must be below the ``<html>`` element of the document,
 stripping out everything else.
 
+See Microsoft???s `XPath Examples 
<https://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx>`__ page for 
some other examples.
+You can also find an XPath of an ``<html>`` node in the Chromium/Google Chrome 
developer tools by right clicking on the node and selecting ``copy XPath``.
+
 
 Filtering based on CSS selectors
 --------------------------------
@@ -301,6 +303,25 @@
          password: urlwatchsecret
      - strip
 
+Dealing with CSV input
+----------------------
+
+`csv2text` filter can be used to turn CSV data to a prettier textual 
representation. This is done by
+supplying a `format_string` which is a [python format 
string](https://docs.python.org/3/library/string.html#format-string-syntax).
+If the CSV has a header, the format string should use the header names 
(**lowercased**). Example:
+
+| Name  | Company |
+|--|--|
+| Smith | Initech |
+| Doe   | Initech |
+
+Format string for the above CSV: `Mr {name} works at {company}` (Note the 
lowercase).
+If there is no header row, you will need to use the numeric array notation:
+`Mr {0} works at {1}`.
+You can also use numeric array on CSV with headers with the flag 
`ignore_header`.
+`has_header` can be used to force use the first line or first ignore the first 
line as header,
+otherwise [csv.Sniffer](https://docs.python.org/3/library/csv.html#csv.Sniffer)
+would be used.
 
 Sorting of webpage content
 --------------------------
@@ -396,6 +417,13 @@
      - xpath: (//a[contains(@class,"item-title ref-name")])[1]
      - html2text
 
+Alternatively, ``jq`` can be used for filtering:
+
+.. code:: yaml
+
+   url: https://api.github.com/repos/voxpupuli/puppet-rundeck/tags
+   filter:
+     - jq: '.[0].name'
 
 Remove or replace text using regular expressions
 ------------------------------------------------
@@ -566,4 +594,4 @@
 Supports aggregations, selections, and the built-in operators like ``length``. 
 For
 more information on the operations permitted, see the `jq Manual`_.
 
-.. _jq Manual: https://stedolan.github.io/jq/manual/
\ No newline at end of file
+.. _jq Manual: https://stedolan.github.io/jq/manual/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/docs/source/jobs.rst 
new/urlwatch-2.24/docs/source/jobs.rst
--- old/urlwatch-2.23/docs/source/jobs.rst      2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/docs/source/jobs.rst      2021-11-07 09:34:54.000000000 
+0100
@@ -7,7 +7,9 @@
 
 The list of jobs to run are contained in the configuration file ``urls.yaml``,
 accessed with the command ``urlwatch --edit``, each separated by a line
-containing only ``---``.
+containing only ``---``. The command ``urlwatch --list`` prints the name
+of each job, along with its index number (1,2,3,...) which gets assigned
+automatically according to its position in the configuration file.
 
 While optional, it is recommended that each job starts with a ``name`` entry:
 
@@ -46,7 +48,6 @@
 - ``ignore_http_error_codes``: List of HTTP errors to ignore (see 
:ref:`advanced_topics`)
 - ``ignore_timeout_errors``: Do not report errors when the timeout is hit
 - ``ignore_too_many_redirects``: Ignore redirect loops (see 
:ref:`advanced_topics`)
-- ``user_visible_url``: Different URL to show in reports (e.g. when watched 
URL is a REST API URL, and you want to show a webpage)
 
 (Note: ``url`` implies ``kind: url``)
 
@@ -130,6 +131,7 @@
 - ``treat_new_as_changed``: Will treat jobs that don't have any historic data 
as ``CHANGED`` instead of ``NEW`` (and create a diff for new jobs)
 - ``compared_versions``: Number of versions to compare for similarity
 - ``kind`` (redundant): Either ``url``, ``shell`` or ``browser``.  
Automatically derived from the unique key (``url``, ``command`` or 
``navigate``) of the job type
+- ``user_visible_url``: Different URL to show in reports (e.g. when watched 
URL is a REST API URL, and you want to show a webpage)
 
 
 Settings keys for all jobs at once
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/docs/source/reporters.rst 
new/urlwatch-2.24/docs/source/reporters.rst
--- old/urlwatch-2.23/docs/source/reporters.rst 2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/docs/source/reporters.rst 2021-11-07 09:34:54.000000000 
+0100
@@ -106,6 +106,17 @@
      chat_id: '88888888' # the chat id where the messages should be sent
      enabled: true
 
+Messages can be sent silently (``silent``) if you prefer notifications
+with no sounds, and monospace formatted (``monospace``).
+By default notifications are not silent and no formatting is done.
+
+.. code:: yaml
+
+   telegram:
+     # ...
+     silent: true # message is sent silently
+     monospace: true # display message as pre-formatted code block
+
 To set up Telegram, from your Telegram app, chat up BotFather (New
 Message, Search, ???BotFather???), then say ``/newbot`` and follow the
 instructions. Eventually it will tell you the bot token (in the form
@@ -173,7 +184,7 @@
       enabled: true
       embed: true
       subject: '{count} changes: {jobs}'
-      
+
 To set up Discord, from your Discord Server settings, select Integration and 
then create a "New Webhook", give the webhook a name to post under, select a 
channel, push "Copy Webhook URL" and paste it into the configuration as seen 
above.
 
 Embedded content might be easier to read and identify individual reports. 
subject preceeds the embedded report and is only used when embed is true.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/__init__.py 
new/urlwatch-2.24/lib/urlwatch/__init__.py
--- old/urlwatch-2.23/lib/urlwatch/__init__.py  2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/lib/urlwatch/__init__.py  2021-11-07 09:34:54.000000000 
+0100
@@ -12,5 +12,5 @@
 __author__ = 'Thomas Perl <[email protected]>'
 __license__ = 'BSD'
 __url__ = 'https://thp.io/2008/urlwatch/'
-__version__ = '2.23'
+__version__ = '2.24'
 __user_agent__ = '%s/%s (+https://thp.io/2008/urlwatch/info.html)' % (pkgname, 
__version__)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/config.py 
new/urlwatch-2.24/lib/urlwatch/config.py
--- old/urlwatch-2.23/lib/urlwatch/config.py    2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/lib/urlwatch/config.py    2021-11-07 09:34:54.000000000 
+0100
@@ -75,6 +75,7 @@
 
         parser = argparse.ArgumentParser(description=urlwatch.__doc__,
                                          
formatter_class=argparse.RawDescriptionHelpFormatter)
+        parser.add_argument('joblist', metavar='JOB', type=int, nargs="*", 
help='index of job(s) to run, as numbered according to the --list command. If 
none specified, then all jobs will be run.')
         parser.add_argument('--version', action='version', version='%(prog)s 
{}'.format(urlwatch.__version__))
         parser.add_argument('-v', '--verbose', action='store_true', help='show 
debug output')
         group = parser.add_argument_group('files and directories')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/filters.py 
new/urlwatch-2.24/lib/urlwatch/filters.py
--- old/urlwatch-2.23/lib/urlwatch/filters.py   2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/lib/urlwatch/filters.py   2021-11-07 09:34:54.000000000 
+0100
@@ -39,6 +39,7 @@
 import sys
 import subprocess
 import io
+import csv
 
 from enum import Enum
 from lxml import etree
@@ -330,6 +331,53 @@
                          method=method, options=options)
 
 
+class Csv2TextFilter(FilterBase):
+    """Convert CSV to plaintext"""
+
+    __kind__ = 'csv2text'
+
+    __supported_subfilters__ = {
+        'format_message': 'A format string with the headers that will be 
outputted for each csv '
+                          'line (header will be lower-cased)',
+        'ignore_header': 'If your format string is number based, but the CSV 
has headers, '
+                         'this flag will force ignoring the header.',
+        'has_header': 'If specified and true - use the first line as a header. 
'
+                      'If false - force ignore first line as header (treat it 
as data). '
+                      'If not specified csv.Sniffer will be used.',
+    }
+
+    __default_subfilter__ = 'format_message'
+
+    def filter(self, data, subfilter):
+        has_header_config = subfilter.get('has_header')
+
+        if has_header_config is None:
+            has_header = csv.Sniffer().has_header(data)
+        else:
+            has_header = has_header_config
+
+        reader = csv.reader(data.split('\n'))
+        data_list = list(reader)
+        header = None
+
+        if has_header:
+            header = data_list.pop(0)
+
+        header = [i.lower() for i in header]
+        message = subfilter['format_message']
+        ignore_header = subfilter['ignore_header']
+
+        lines = []
+        for i in data_list:
+            if header and not ignore_header:
+                legend = dict(zip(header, i))
+                lines.append(message.format(**legend))
+            else:
+                lines.append(message.format(*i))
+
+        return '\n'.join(lines)
+
+
 class Pdf2TextFilter(FilterBase):
     """Convert PDF to plaintext"""
     # Requires data to be in bytes (not unicode)
@@ -809,6 +857,31 @@
         return separator.join(sorted(data.split(separator), key=str.casefold, 
reverse=reverse))
 
 
+class RemoveDuplicateLinesFilter(FilterBase):
+    """Remove duplicate lines"""
+
+    __kind__ = 'remove-duplicate-lines'
+
+    __supported_subfilters__ = {
+        'separator': 'Item separator (default: newline)',
+    }
+
+    __default_subfilter__ = 'separator'
+
+    def filter(self, data, subfilter):
+        separator = subfilter.get('separator', '\n')
+        data_lines = data.split(separator)
+
+        def get_unique_lines(lines):
+            seen = set()
+            for line in lines:
+                if line not in seen:
+                    yield line
+                    seen.add(line)
+
+        return separator.join(get_unique_lines(data_lines))
+
+
 class ReverseFilter(FilterBase):
     """Reverse input items"""
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/jobs.py 
new/urlwatch-2.24/lib/urlwatch/jobs.py
--- old/urlwatch-2.23/lib/urlwatch/jobs.py      2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/lib/urlwatch/jobs.py      2021-11-07 09:34:54.000000000 
+0100
@@ -180,10 +180,11 @@
 
 class Job(JobBase):
     __required__ = ()
-    __optional__ = ('name', 'filter', 'max_tries', 'diff_tool', 
'compared_versions', 'diff_filter', 'treat_new_as_changed')
+    __optional__ = ('name', 'filter', 'max_tries', 'diff_tool', 
'compared_versions', 'diff_filter', 'treat_new_as_changed', 'user_visible_url')
 
     # determine if hyperlink "a" tag is used in HtmlReporter
-    LOCATION_IS_URL = False
+    def location_is_url(self):
+        return re.match("^([a-zA-Z0-9+.-]+)://", self.get_location())
 
     def pretty_name(self):
         return self.name if self.name else self.get_location()
@@ -198,7 +199,7 @@
     __optional__ = ()
 
     def get_location(self):
-        return self.command
+        return self.user_visible_url or self.command
 
     def retrieve(self, job_state):
         process = subprocess.Popen(self.command, stdout=subprocess.PIPE, 
shell=True)
@@ -221,9 +222,8 @@
     __required__ = ('url',)
     __optional__ = ('cookies', 'data', 'method', 'ssl_no_verify', 
'ignore_cached', 'http_proxy', 'https_proxy',
                     'headers', 'ignore_connection_errors', 
'ignore_http_error_codes', 'encoding', 'timeout',
-                    'ignore_timeout_errors', 'ignore_too_many_redirects', 
'user_visible_url')
+                    'ignore_timeout_errors', 'ignore_too_many_redirects')
 
-    LOCATION_IS_URL = True
     CHARSET_RE = re.compile('text/(html|plain); charset=([^;]*)')
 
     def get_location(self):
@@ -251,12 +251,14 @@
             headers['Cache-Control'] = 'max-age=172800'
             headers['Expires'] = email.utils.formatdate()
 
-        if self.method is None:
-            self.method = "GET"
         if self.data is not None:
-            self.method = "POST"
+            if self.method is None:
+                self.method = "POST"
             headers['Content-type'] = 'application/x-www-form-urlencoded'
-            logger.info('Sending POST request to %s', self.url)
+            logger.info('Sending %s request to %s', self.method, self.url)
+
+        if self.method is None:
+            self.method = "GET"
 
         if self.http_proxy is not None:
             proxies['http'] = self.http_proxy
@@ -366,10 +368,8 @@
 
     __optional__ = ('wait_until',)
 
-    LOCATION_IS_URL = True
-
     def get_location(self):
-        return self.navigate
+        return self.user_visible_url or self.navigate
 
     def main_thread_enter(self):
         from .browser import BrowserContext
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/mailer.py 
new/urlwatch-2.24/lib/urlwatch/mailer.py
--- old/urlwatch-2.23/lib/urlwatch/mailer.py    2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/lib/urlwatch/mailer.py    2021-11-07 09:34:54.000000000 
+0100
@@ -95,6 +95,8 @@
                 if passwd is None:
                     raise ValueError('No password available in keyring for {}, 
{}'
                                      .format(self.smtp_server, self.smtp_user))
+            else:
+                raise ValueError('SMTP auth is enabled, but insecure_password 
is not set and keyring is not available')
             s.login(self.smtp_user, passwd)
 
         s.sendmail(msg['From'], msg['To'].split(','), msg.as_string())
@@ -106,7 +108,7 @@
         self.sendmail_path = sendmail_path
 
     def send(self, msg):
-        p = subprocess.Popen([self.sendmail_path, '-oi', msg['To']],
+        p = subprocess.Popen([self.sendmail_path, '-oi', '-f', msg['From'], 
msg['To']],
                              stdin=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              universal_newlines=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/reporters.py 
new/urlwatch-2.24/lib/urlwatch/reporters.py
--- old/urlwatch-2.23/lib/urlwatch/reporters.py 2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/lib/urlwatch/reporters.py 2021-11-07 09:34:54.000000000 
+0100
@@ -183,7 +183,7 @@
         for job_state in self.report.get_filtered_job_states(self.job_states):
             job = job_state.job
 
-            if job.LOCATION_IS_URL:
+            if job.location_is_url():
                 title = '<a href="{location}">{pretty_name}</a>'
             elif job.pretty_name() != job.get_location():
                 title = '<span title="{location}">{pretty_name}</span>'
@@ -600,11 +600,29 @@
 
         return result
 
+    @staticmethod
+    def _format_body(text: str) -> str:
+        return "```diff\n{}\n```".format(
+            text.translate(str.maketrans({'`': r'\`', '\\': r'\\'})))
+
     def submitToTelegram(self, bot_token, chat_id, text):
         logger.debug("Sending telegram request to chat 
id:'{0}'".format(chat_id))
-        result = requests.post(
-            "https://api.telegram.org/bot{0}/sendMessage".format(bot_token),
-            data={"chat_id": chat_id, "text": text, 
"disable_web_page_preview": "true"})
+
+        data = {"chat_id": chat_id,
+                "text": text,
+                "disable_notification": self.config.get('silent', False),
+                "disable_web_page_preview": True}
+
+        if self.config.get('monospace', False):
+            # all "`" and "\" characters are escaped and text is put inside
+            # a markdown code block. API docs on formatting messages:
+            # https://core.telegram.org/bots/api#formatting-options
+            data.update({
+                "text": self._format_body(text),
+                "parse_mode": "MarkdownV2"
+            })
+
+        result = 
requests.post("https://api.telegram.org/bot{0}/sendMessage".format(bot_token), 
json=data)
         try:
             json_res = result.json()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/storage.py 
new/urlwatch-2.24/lib/urlwatch/storage.py
--- old/urlwatch-2.23/lib/urlwatch/storage.py   2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/lib/urlwatch/storage.py   2021-11-07 09:34:54.000000000 
+0100
@@ -126,6 +126,8 @@
             'enabled': False,
             'bot_token': '',
             'chat_id': '',
+            'monospace': False,
+            'silent': False,
         },
         'slack': {
             'enabled': False,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/urlwatch-2.23/lib/urlwatch/tests/data/filter_documentation_testdata.yaml 
new/urlwatch-2.24/lib/urlwatch/tests/data/filter_documentation_testdata.yaml
--- 
old/urlwatch-2.23/lib/urlwatch/tests/data/filter_documentation_testdata.yaml    
    2021-04-10 10:48:22.000000000 +0200
+++ 
new/urlwatch-2.24/lib/urlwatch/tests/data/filter_documentation_testdata.yaml    
    2021-11-07 09:34:54.000000000 +0100
@@ -368,7 +368,33 @@
         "company": "Initech"
       }
     ]
-  output: |
+  output: |-
       "Senior Data Scientist"
       "Python Developer"
-      "TPS Report Analyst"
\ No newline at end of file
+      "TPS Report Analyst"
+https://api.github.com/repos/voxpupuli/puppet-rundeck/tags:
+  input: |
+    [
+      {
+        "name": "v6.0.0",
+        "zipball_url": 
"https://api.github.com/repos/voxpupuli/puppet-rundeck/zipball/refs/tags/v6.0.0";,
+        "tarball_url": 
"https://api.github.com/repos/voxpupuli/puppet-rundeck/tarball/refs/tags/v6.0.0";,
+        "commit": {
+          "sha": "f539fb125f8fe56cec4f134dd5ef4b5c9be961c5",
+          "url": 
"https://api.github.com/repos/voxpupuli/puppet-rundeck/commits/f539fb125f8fe56cec4f134dd5ef4b5c9be961c5";
+        },
+        "node_id": "MDM6UmVmMTgyMDczMjM6cmVmcy90YWdzL3Y2LjAuMA=="
+      },
+      {
+        "name": "v5.4.0",
+        "zipball_url": 
"https://api.github.com/repos/voxpupuli/puppet-rundeck/zipball/refs/tags/v5.4.0";,
+        "tarball_url": 
"https://api.github.com/repos/voxpupuli/puppet-rundeck/tarball/refs/tags/v5.4.0";,
+        "commit": {
+          "sha": "4689cde2189ac38a36c81275fb13925f5c4a8ca2",
+          "url": 
"https://api.github.com/repos/voxpupuli/puppet-rundeck/commits/4689cde2189ac38a36c81275fb13925f5c4a8ca2";
+        },
+        "node_id": "MDM6UmVmMTgyMDczMjM6cmVmcy90YWdzL3Y1LjQuMA=="
+      }
+    ]
+  output: |-
+    "v6.0.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/tests/test_handler.py 
new/urlwatch-2.24/lib/urlwatch/tests/test_handler.py
--- old/urlwatch-2.23/lib/urlwatch/tests/test_handler.py        2021-04-10 
10:48:22.000000000 +0200
+++ new/urlwatch-2.24/lib/urlwatch/tests/test_handler.py        2021-11-07 
09:34:54.000000000 +0100
@@ -11,7 +11,7 @@
 import os
 
 from urlwatch import storage
-from urlwatch.config import BaseConfig
+from urlwatch.config import CommandConfig
 from urlwatch.storage import YamlConfigStorage, CacheMiniDBStorage
 from urlwatch.main import Urlwatch
 from urlwatch.util import import_module_from_source
@@ -87,12 +87,10 @@
     assert result.total_errors == 0, "Found #{0} code style 
errors".format(result.total_errors)
 
 
-class ConfigForTest(BaseConfig):
+class ConfigForTest(CommandConfig):
     def __init__(self, config, urls, cache, hooks, verbose):
         (prefix, bindir) = 
os.path.split(os.path.dirname(os.path.abspath(sys.argv[0])))
-        super().__init__('urlwatch', os.path.dirname(__file__), config, urls, 
cache, hooks, verbose)
-        self.edit = False
-        self.edit_hooks = False
+        super().__init__('urlwatch', os.path.dirname(__file__), bindir, 
prefix, config, urls, hooks, cache, verbose)
 
 
 @contextlib.contextmanager
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urlwatch-2.23/lib/urlwatch/worker.py 
new/urlwatch-2.24/lib/urlwatch/worker.py
--- old/urlwatch-2.23/lib/urlwatch/worker.py    2021-04-10 10:48:22.000000000 
+0200
+++ new/urlwatch-2.24/lib/urlwatch/worker.py    2021-11-07 09:34:54.000000000 
+0100
@@ -51,12 +51,14 @@
 
 
 def run_jobs(urlwatcher):
+    if not all(1 <= idx <= len(urlwatcher.jobs) for idx in 
urlwatcher.urlwatch_config.joblist):
+        raise ValueError(f'All job indices must be between 1 and 
{len(urlwatcher.jobs)}: {urlwatcher.urlwatch_config.joblist}')
     cache_storage = urlwatcher.cache_storage
     jobs = [job.with_defaults(urlwatcher.config_storage.config)
-            for job in urlwatcher.jobs]
+            for (idx, job) in enumerate(urlwatcher.jobs) if ((idx + 1) in 
urlwatcher.urlwatch_config.joblist or (not urlwatcher.urlwatch_config.joblist))]
     report = urlwatcher.report
 
-    logger.debug('Processing %d jobs', len(jobs))
+    logger.debug('Processing %d jobs (out of %d)', len(jobs), 
len(urlwatcher.jobs))
     with contextlib.ExitStack() as exit_stack:
         for job_state in run_parallel(lambda job_state: job_state.process(),
                                       
(exit_stack.enter_context(JobState(cache_storage, job)) for job in jobs)):

Reply via email to