build environment improvements (#1385)

pull/1395/head
Chris Caron 2025-08-16 18:19:33 -04:00 committed by GitHub
parent 92d5d7cc8a
commit c15243a9cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 249 additions and 70 deletions

View File

@ -39,7 +39,7 @@ jobs:
with: with:
name: built-rpms name: built-rpms
path: | path: |
dist/**/*.rpm dist/rpm/*/*.rpm
if-no-files-found: error if-no-files-found: error
retention-days: 5 retention-days: 5

1
.gitignore vendored
View File

@ -17,6 +17,7 @@ __pycache__/
env/ env/
.venv* .venv*
build/ build/
BUILD/
BUILDROOT/ BUILDROOT/
SOURCES/ SOURCES/
SRPMS/ SRPMS/

22
.vscode/settings.json vendored
View File

@ -1,9 +1,17 @@
{ {
"python.testing.pytestArgs": [], "python.testing.pytestArgs": [
"python.testing.cwd": "${workspaceFolder}", "tests"
"python.testing.unittestEnabled": false, ],
"python.testing.pytestEnabled": true, "python.linting.enabled": true,
"terminal.integrated.env.linux": { "python.linting.ruffEnabled": true,
"PYTHONPATH": "${workspaceFolder}" "python.linting.ruffPath": "ruff",
} "python.formatting.provider": "none",
"editor.formatOnSave": true,
"python.testing.cwd": "${workspaceFolder}",
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"python.envFile": "${workspaceFolder}/.env",
"terminal.integrated.env.linux": {
"PYTHONPATH": "${workspaceFolder}"
}
} }

View File

@ -20,19 +20,87 @@ merge your contributions smoothly.
tox -e qa tox -e qa
``` ```
- ✔️ All tests pass locally.
- ✔️ Your code is clean and consistently formatted: - ✔️ Your code is clean and consistently formatted:
```bash ```bash
tox -e format tox -e format
``` ```
- ✔️ You followed the plugin template (if adding a new plugin). - ✔️ You followed the plugin template (if adding a new plugin).
- ✔️ You included inline docstrings and respected the BSD 2-Clause license. - ✔️ You included inline docstrings and respected the BSD 2-Clause license.
- ✔️ Your commit message is descriptive. - ✔️ Your commit message is descriptive.
--- ---
## 📦 Local Development Setup
To get started with development:
### 🧰 System Requirements
- Python >= 3.9
- `pip`
- `git`
- Optional: `VS Code` with the Python extension
### 🚀 One-Time Setup
```bash
git clone https://github.com/caronc/apprise.git
cd apprise
# Install all runtime + dev dependencies
pip install .[dev]
```
(Optional, but recommended if actively developing):
```bash
pip install -e .[dev]
```
---
## 🧪 Running Tests
```bash
pytest # Run all tests
pytest tests/foo.py # Run a specific test file
```
Run with coverage:
```bash
pytest --cov=apprise --cov-report=term
```
---
## 🧹 Linting & Formatting with ruff
```bash
ruff check apprise tests # Check linting
ruff check apprise tests --fix # Auto-fix
ruff format apprise tests # Format files
```
---
## 🧰 Optional: Using VS Code
1. Open the repo: `code .`
2. Press `Ctrl+Shift+P → Python: Select Interpreter`
3. Choose the same interpreter you used for `pip install .[dev]`
4. Press `Ctrl+Shift+P → Python: Discover Tests`
`.vscode/settings.json` is pre-configured with:
- pytest as the test runner
- ruff for linting
- PYTHONPATH set to project root
No `.venv` is required unless you choose to use one.
---
## 📌 How to Contribute ## 📌 How to Contribute
1. **Fork the repository** and create a new branch. 1. **Fork the repository** and create a new branch.

View File

@ -10,6 +10,9 @@ include dev-requirements.txt
include all-plugin-requirements.txt include all-plugin-requirements.txt
recursive-include tests * recursive-include tests *
recursive-include packaging * recursive-include packaging *
recursive-include apprise/i18n *.pot
recursive-include apprise/i18n *.po
recursive-include apprise/i18n */LC_MESSAGES/*.po
global-exclude *.pyc global-exclude *.pyc
global-exclude *.pyo global-exclude *.pyo
global-exclude __pycache__ global-exclude __pycache__

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: apprise 1.4.5\n" "Project-Id-Version: apprise 1.4.5\n"
"Report-Msgid-Bugs-To: lead2gold@gmail.com\n" "Report-Msgid-Bugs-To: lead2gold@gmail.com\n"
"POT-Creation-Date: 2025-08-02 17:51+0000\n" "POT-Creation-Date: 2025-08-03 13:22+0000\n"
"PO-Revision-Date: 2019-05-24 20:00-0400\n" "PO-Revision-Date: 2019-05-24 20:00-0400\n"
"Last-Translator: Chris Caron <lead2gold@gmail.com>\n" "Last-Translator: Chris Caron <lead2gold@gmail.com>\n"
"Language: en\n" "Language: en\n"

View File

View File

@ -27,56 +27,60 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -euo pipefail
# Set Apprise root directory # Set Apprise root directory
APPRISE_DIR="${APPRISE_DIR:-/apprise}" APPRISE_DIR="${APPRISE_DIR:-/apprise}"
DIST_DIR="${DIST_DIR:-$PWD/dist/rpm}"
SOURCES_DIR="$APPRISE_DIR/SOURCES"
SRPM_DIR="$DIST_DIR/"
PYTHON=python3 PYTHON=python3
TOX="tox -c $APPRISE_DIR/tox.ini" TOX="tox -c $APPRISE_DIR/tox.ini"
DIST_DIR="${DIST_DIR:-$PWD/dist}"
mkdir -p "$DIST_DIR"
echo "==> Cleaning previous builds" if [ ! -d "$DIST_DIR" ]; then
$TOX -e clean --notest echo "==> Cleaning previous builds"
$TOX -e clean --notest
echo "==> Linting RPM spec" echo "==> Linting RPM spec"
rpmlint "$APPRISE_DIR/packaging/redhat/python-apprise.spec" rpmlint "$APPRISE_DIR/packaging/redhat/python-apprise.spec"
echo "==> Running tests" echo "==> Generating man pages"
$TOX -e py312 ronn --roff --organization="Chris Caron <lead2gold@gmail.com>" \
"$APPRISE_DIR/packaging/man/apprise.md"
echo "==> Generating man pages" echo "==> Extracting translations"
ronn --roff --organization="Chris Caron <lead2gold@gmail.com>" \ $TOX -e i18n
"$APPRISE_DIR/packaging/man/apprise.md"
echo "==> Extracting translations" echo "==> Compiling translations"
$TOX -e i18n || { echo "Translation extraction failed!" ; exit 1; } $TOX -e compile
echo "==> Compiling translations" echo "==> Building source distribution"
$TOX -e compile || { echo "Translation compilation failed!" ; exit 1; } $TOX -e build-sdist
fi
echo "==> Building source distribution"
$TOX -e build-sdist || { echo "sdist build failed!" ; exit 1; }
VERSION=$(rpmspec -q --qf "%{version}\n" "$APPRISE_DIR/packaging/redhat/python-apprise.spec" | head -n1) VERSION=$(rpmspec -q --qf "%{version}\n" "$APPRISE_DIR/packaging/redhat/python-apprise.spec" | head -n1)
TARBALL="$APPRISE_DIR/dist/apprise-${VERSION}.tar.gz" TARBALL="$APPRISE_DIR/dist/apprise-${VERSION}.tar.gz"
if [[ ! -f "$TARBALL" ]]; then if [[ ! -f "$TARBALL" ]]; then
echo "Tarball not found: $TARBALL" echo "Tarball not found: $TARBALL"
exit 1 exit 1
fi fi
echo "==> Copying tarball to SOURCES directory" echo "==> Preparing SOURCES directory"
mkdir -p "$APPRISE_DIR/SOURCES" mkdir -p "$SOURCES_DIR"
cp "$TARBALL" "$APPRISE_DIR/SOURCES/" cp "$TARBALL" "$SOURCES_DIR/"
find $APPRISE_DIR/packaging/redhat/ -iname '*.patch' -exec cp {} "$SOURCES_DIR" \;
echo "==> Building RPM" echo "==> Building RPM (source and binary)"
mkdir -p "$DIST_DIR"
rpmbuild --define "_topdir $APPRISE_DIR" \ rpmbuild --define "_topdir $APPRISE_DIR" \
--define "_sourcedir $APPRISE_DIR/SOURCES" \ --define "_sourcedir $SOURCES_DIR" \
--define "_specdir $APPRISE_DIR/packaging/redhat" \ --define "_specdir $APPRISE_DIR/packaging/redhat" \
--define "_srcrpmdir $APPRISE_DIR/SRPMS" \ --define "_srcrpmdir $DIST_DIR" \
--define "_rpmdir $DIST_DIR" \ --define "_rpmdir $DIST_DIR" \
-ba "$APPRISE_DIR/packaging/redhat/python-apprise.spec" -ba "$APPRISE_DIR/packaging/redhat/python-apprise.spec"
echo "✅ RPM build completed successfully" echo "✅ RPM build completed successfully"
echo "📦 Artifacts:"
find "$DIST_DIR" -type f -name "*.rpm"

19
codecov.yml Normal file
View File

@ -0,0 +1,19 @@
codecov:
require_ci_to_pass: false
comment:
layout: "reach,diff,flags,files"
require_changes: false
behavior: update
after_n_builds: 1
coverage:
status:
project:
default:
target: auto
threshold: 1%
patch:
default:
target: auto
threshold: 1%

View File

@ -5,6 +5,8 @@ services:
dockerfile: tests/docker/Dockerfile.py39 dockerfile: tests/docker/Dockerfile.py39
volumes: volumes:
- ./:/apprise - ./:/apprise
working_dir: /apprise
user: "1000:1000"
test.py310: test.py310:
build: build:
@ -12,6 +14,8 @@ services:
dockerfile: tests/docker/Dockerfile.py310 dockerfile: tests/docker/Dockerfile.py310
volumes: volumes:
- ./:/apprise - ./:/apprise
working_dir: /apprise
user: "1000:1000"
test.py311: test.py311:
build: build:
@ -19,6 +23,8 @@ services:
dockerfile: tests/docker/Dockerfile.py311 dockerfile: tests/docker/Dockerfile.py311
volumes: volumes:
- ./:/apprise - ./:/apprise
working_dir: /apprise
user: "1000:1000"
test.py312: test.py312:
build: build:
@ -26,6 +32,8 @@ services:
dockerfile: tests/docker/Dockerfile.py312 dockerfile: tests/docker/Dockerfile.py312
volumes: volumes:
- ./:/apprise - ./:/apprise
working_dir: /apprise
user: "1000:1000"
rpmbuild.el9: rpmbuild.el9:
build: build:
@ -33,6 +41,8 @@ services:
dockerfile: tests/docker/Dockerfile.el9 dockerfile: tests/docker/Dockerfile.el9
volumes: volumes:
- ./:/apprise - ./:/apprise
working_dir: /apprise
user: "1000:1000"
rpmbuild.f42: rpmbuild.f42:
build: build:
@ -40,6 +50,8 @@ services:
dockerfile: tests/docker/Dockerfile.f42 dockerfile: tests/docker/Dockerfile.f42
volumes: volumes:
- ./:/apprise - ./:/apprise
working_dir: /apprise
user: "1000:1000"
rpmbuild.rawhide: rpmbuild.rawhide:
build: build:
@ -47,6 +59,8 @@ services:
dockerfile: tests/docker/Dockerfile.rawhide dockerfile: tests/docker/Dockerfile.rawhide
volumes: volumes:
- ./:/apprise - ./:/apprise
working_dir: /apprise
user: "1000:1000"
# #
# Every Day testing # Every Day testing

View File

@ -1,6 +1,8 @@
## Packaging ## Packaging
This directory contains any supporting files to grant usage of Apprise in various distributions. This directory contains any supporting files to grant usage of Apprise in various distributions.
Let me know if you'd like to help me host on more platforms or can offer to do it yourself!
### RPM Based Packages ### RPM Based Packages
* [EPEL](https://fedoraproject.org/wiki/EPEL) based distributions are only supported if they are of v9 or higher. This includes: * [EPEL](https://fedoraproject.org/wiki/EPEL) based distributions are only supported if they are of v9 or higher. This includes:
* Red Hat 9.x (or higher) * Red Hat 9.x (or higher)
@ -17,7 +19,17 @@ Provided you are connected to the [EPEL repositories](https://fedoraproject.org/
dnf install python3-apprise apprise dnf install python3-apprise apprise
``` ```
Let me know if you'd like to help me host on more platforms or can offer to do it yourself! You can build your own rpm packges with the following:
```bash
# EPEL9 (CentOS/Rocky/RedHat/Oracle Linux)
tox -e build-el9-rpm
# Fedora 42
tox -e build-f42-rpm
# Fedora Rawhide
tox -e build-rawhide-rpm
```
## Man Pages Information ## Man Pages Information
The man page were generated using [Ronn](http://github.com/rtomayko/ronn/tree/0.7.3). The man page were generated using [Ronn](http://github.com/rtomayko/ronn/tree/0.7.3).

View File

@ -79,7 +79,7 @@ notification services. It supports sending alerts to platforms such as: \
Name: python-%{pypi_name} Name: python-%{pypi_name}
Version: 1.9.4 Version: 1.9.4
Release: 1%{?dist} Release: 3%{?dist}
Summary: A simple wrapper to many popular notification services used today Summary: A simple wrapper to many popular notification services used today
License: BSD-2-Clause License: BSD-2-Clause
URL: https://github.com/caronc/%{pypi_name} URL: https://github.com/caronc/%{pypi_name}
@ -147,17 +147,7 @@ BuildRequires: python%{python3_pkgversion}-pytest-cov
%description -n python%{python3_pkgversion}-%{pypi_name} %{common_description} %description -n python%{python3_pkgversion}-%{pypi_name} %{common_description}
%prep %prep
%setup -q -n %{pypi_name}-%{version} %autosetup -n %{pypi_name}-%{version}
# 2023.08.27: This test fails for some uknown reason only during the test
# section of this RPM, but works completley fine under all other circumstances.
# As a workaround, just remove the file so it doesn't hold up the RPM
# Preparation
%{__rm} tests/test_plugin_bulksms.py
# 2023.08.27: rawhide does not install translationfiles for some reason
# at this time; remove failing test until this is resolved
%{__rm} tests/test_apprise_translations.py
%build %build
%if %{legacy_python_build} %if %{legacy_python_build}
@ -167,13 +157,13 @@ BuildRequires: python%{python3_pkgversion}-pytest-cov
%pyproject_wheel %pyproject_wheel
%endif %endif
%install %install
%if %{legacy_python_build} %if %{legacy_python_build}
# backwards compatible # backwards compatible
%py3_install %py3_install
%else %else
%pyproject_install %pyproject_install
%pyproject_save_files apprise
%endif %endif
%{__install} -p -D -T -m 0644 packaging/man/%{pypi_name}.1 \ %{__install} -p -D -T -m 0644 packaging/man/%{pypi_name}.1 \
@ -205,7 +195,7 @@ LANG=C.UTF-8 PYTHONPATH=%{buildroot}%{python3_sitelib}:%{_builddir}/%{name}-%{ve
%endif %endif
# Localised Files # Localised Files
%lang(en) %{python3_sitelib}/%{pypi_name}/i18n/en/LC_MESSAGES/messages.mo %lang(en) %{python3_sitelib}/%{pypi_name}/i18n/en/LC_MESSAGES/apprise.mo
%files -n %{pypi_name} %files -n %{pypi_name}
%{_bindir}/%{pypi_name} %{_bindir}/%{pypi_name}
@ -214,6 +204,12 @@ LANG=C.UTF-8 PYTHONPATH=%{buildroot}%{python3_sitelib}:%{_builddir}/%{name}-%{ve
%{python3_sitelib}/%{pypi_name}/__pycache__/cli*.py? %{python3_sitelib}/%{pypi_name}/__pycache__/cli*.py?
%changelog %changelog
* Sat Aug 16 2025 Chris Caron <lead2gold@gmail.com> - 1.9.4-3
- Spec file modernization BZ2377453
* Fri Aug 15 2025 Python Maint <python-maint@redhat.com> - 1.9.4-2
- Rebuilt for Python 3.14.0rc2 bytecode
* Sat Aug 2 2025 Chris Caron <lead2gold@gmail.com> - 1.9.4 * Sat Aug 2 2025 Chris Caron <lead2gold@gmail.com> - 1.9.4
- Updated to v1.9.4 - Updated to v1.9.4

View File

@ -347,11 +347,11 @@ section-order = ["future", "standard-library", "third-party", "first-party", "lo
builtins-ignorelist = ["_"] builtins-ignorelist = ["_"]
[tool.pytest.ini_options] [tool.pytest.ini_options]
addopts = "-ra" # Keep pytest-cov minimal, let Coverage.py control formatting.
python_files = ["tests/test_*.py"] addopts = "-ra --cov=apprise --cov-branch --cov-report=xml"
filterwarnings = ["once::Warning"]
norecursedirs = ["tests/helpers", "dist", ".tox", ".venv", ".eggs", ".local", "venv"]
testpaths = ["tests"] testpaths = ["tests"]
python_files = ["test_*.py", "tests/test_*.py"]
filterwarnings = ["once::Warning"]
[tool.coverage.run] [tool.coverage.run]
branch = true branch = true
@ -361,6 +361,7 @@ source = ["apprise"]
relative_files = true relative_files = true
[tool.coverage.paths] [tool.coverage.paths]
# Normalise .tox and site-packages layouts back to 'apprise'
source = [ source = [
"apprise", "apprise",
"/apprise/apprise", "/apprise/apprise",
@ -369,6 +370,20 @@ source = [
] ]
[tool.coverage.report] [tool.coverage.report]
# Controls terminal and XML content when Coverage.py renders reports
show_missing = true show_missing = true
skip_covered = true skip_covered = true
skip_empty = true skip_empty = true
precision = 1
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",
"if __name__ == .__main__.:",
"raise NotImplementedError",
"pass$",
]
[tool.coverage.xml]
# Ensure GitHub Action can find a predictable file
output = "coverage.xml"

65
tox.ini
View File

@ -7,13 +7,12 @@ use_discover = False
[tox] [tox]
envlist = envlist =
clean clean
validate
i18n i18n
compile compile
minimal minimal
build
release release
validate
twine-check
minversion = 4.0 minversion = 4.0
requires = virtualenv>=20.0.0 requires = virtualenv>=20.0.0
isolated_build = True isolated_build = True
@ -27,13 +26,54 @@ ensurepip = true
setenv = setenv =
COVERAGE_RCFILE = {toxinidir}/pyproject.toml COVERAGE_RCFILE = {toxinidir}/pyproject.toml
[testenv:build-rpm] [testenv:build-src-rpm]
description = Run RPM packaging via Docker description = Build source RPM and place .src.rpm in dist/
skip_install = true
allowlist_externals =
bash
cp
mkdir
find
rpmbuild
setenv =
HOME = {envtmpdir}
RPMTOP = {envtmpdir}/rpmbuild
commands_pre =
mkdir -p {envtmpdir}/rpmbuild/SOURCES
mkdir -p {envtmpdir}/rpmbuild/SPECS
mkdir -p dist/rpm
cp packaging/man/apprise.1 {envtmpdir}/rpmbuild/SOURCES/
cp packaging/redhat/python-apprise.spec {envtmpdir}/rpmbuild/SPECS/
find packaging/redhat/ -iname '*.patch' -exec cp {} {envtmpdir}/rpmbuild/SOURCES/ \;
bash -c 'cp dist/*.tar.gz {envtmpdir}/rpmbuild/SOURCES/'
bash -c 'echo "%_topdir {envtmpdir}/rpmbuild" > {envtmpdir}/.rpmmacros'
commands =
rpmbuild --nodeps -bs {envtmpdir}/rpmbuild/SPECS/python-apprise.spec
find {envtmpdir}/rpmbuild/SRPMS -name '*.src.rpm' -exec mv {} dist/rpm \;
[testenv:build-el9-rpm]
description = Run RPM packaging for EPEL9 via Docker
skip_install = true
allowlist_externals = allowlist_externals =
docker docker
bash
commands = commands =
docker compose run --user root --rm rpmbuild.el9 bash build-rpm.sh docker compose run --rm rpmbuild.el9 bash /usr/bin/build-rpm.sh
[testenv:build-f42-rpm]
description = Run RPM packaging for Fedora 42 via Docker
skip_install = true
allowlist_externals =
docker
commands =
docker compose run --rm rpmbuild.f42 bash /usr/bin/build-rpm.sh
[testenv:build-rawhide-rpm]
description = Run RPM packaging for Fedora Rawhide via Docker
skip_install = true
allowlist_externals =
docker
commands =
docker compose run --rm rpmbuild.rawhide bash /usr/bin/build-rpm.sh
[testenv:lint] [testenv:lint]
description = Run static analysis using Ruff description = Run static analysis using Ruff
@ -104,8 +144,10 @@ commands =
find . -type f -name "*.pyc" -delete find . -type f -name "*.pyc" -delete
find . -type f -name "*.pyo" -delete find . -type f -name "*.pyo" -delete
find . -type f -name "*.orig" -delete find . -type f -name "*.orig" -delete
find . -type f -name "*.orig" -delete
find ./apprise/i18n -type f -name "*.mo" -delete
rm -rf BUILD SOURCES SRPMS BUILDROOT .cache .ruff_cache .coverage-reports .coverage coverage.xml dist build apprise.egg-info .mypy_cache .pytest_cache "__pycache__"
find . -type d -name "__pycache__" -delete find . -type d -name "__pycache__" -delete
rm -rf BUILD SOURCES SRPMS BUILDROOT .cache .ruff_cache .coverage-reports .coverage coverage.xml dist build apprise.egg-info .mypy_cache .pytest_cache
[testenv:i18n] [testenv:i18n]
description = Extract and update .pot/.po files for translation description = Extract and update .pot/.po files for translation
@ -115,13 +157,13 @@ ensurepip = true
commands = commands =
mkdir -p apprise/i18n mkdir -p apprise/i18n
pybabel extract -F babel.cfg -o apprise/i18n/apprise.pot apprise pybabel extract -F babel.cfg -o apprise/i18n/apprise.pot apprise
pybabel update -i apprise/i18n/apprise.pot -d apprise/i18n pybabel update --domain=apprise -i apprise/i18n/apprise.pot -d apprise/i18n
[testenv:compile] [testenv:compile]
description = Compile .mo files description = Compile .mo files
deps = Babel deps = Babel
commands = commands =
pybabel compile -d apprise/i18n pybabel compile --domain=apprise -d apprise/i18n
[testenv:build] [testenv:build]
description = Build sdist and wheel (assumes translations compiled) description = Build sdist and wheel (assumes translations compiled)
@ -151,11 +193,8 @@ commands =
[testenv:twine-check] [testenv:twine-check]
description = Run twine check on dist artifacts description = Run twine check on dist artifacts
deps = deps =
build
twine twine
commands = commands =
rm -rf dist
python -m build
twine check dist/* twine check dist/*
[testenv:man] [testenv:man]