Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- name: Check out repository
Expand Down Expand Up @@ -100,7 +100,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- name: Check out repository
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ tools/

# Release artifacts
releases/
dist/
build/
*.zip
*.exe
*.msix
SHA256SUMS.txt

# Marketing & automation logs (never track in repository per GITHUB-POLICY)
MARKETING-LOG.txt
*.receipt.json

# Sync & patch artifacts
*.sync-conflict-*
*.conflict
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

### Maintenance

- **Technical Hygiene, PEP 639 License Standardization & Git Tracking Protection (2026-10-31)**:
- **Git Tracking Protection & .gitignore Hardening**: Untracked `MARKETING-LOG.txt` from git repository index and updated `.gitignore` to strictly exclude `MARKETING-LOG.txt`, `*.receipt.json`, `dist/`, and `build/`, enforcing GITHUB-POLICY zero-pollution requirements.
- **PEP 639 License Compliance**: Modernized `pyproject.toml` with `license = "MIT"` and `license-files = ["LICENSE"]`, removing redundant `"License :: OSI Approved :: MIT License"` classifier to prevent `InvalidConfigError` in modern setuptools, and declared Python 3.13 support.
- **CI Workflow Hardening**: Expanded multi-OS `source-smoke` and Windows test matrices in `.github/workflows/tests.yml` to include Python 3.13.
- **Contract Test Suite Expansion**: Updated `tests/test_metadata.py` with automated assertions for PEP 639 license structure, absence of conflicting OSI classifiers, `.gitignore` log protection, and untracked status of `MARKETING-LOG.txt` (106/106 tests passing, 100% green).


- **Technical Hygiene, CI Workflow Hardening & Metadata Contract Suite (2026-09-06)**:
- **CI Workflow Hardening**: Upgraded `.github/workflows/tests.yml` to official stable actions (`actions/checkout@v4`, `actions/setup-python@v5` with pip cache), added concurrency control with `cancel-in-progress: true`, added a dedicated `ruff check .` linting gate on Windows, and added a multi-OS `source-smoke` matrix job across Ubuntu and macOS for Python 3.10-3.12 executing `source_platform_smoke.py` and `test_source_platform_smoke_contract.py`.
- **PEP 621 Metadata**: Enhanced `pyproject.toml` with standard classifiers (`Environment :: Win32 (MS Windows)`, `Environment :: X11 Applications :: Qt`, `Topic :: Communications :: Email`, `Topic :: Desktop Environment`, `Topic :: Utilities`), complete ecosystem URLs (Homepage, Repository, Bug Tracker, Changelog, Documentation, Security, Parent Organization, Umbrella Ecosystem), and `[tool.ruff]` configuration.
Expand Down
50 changes: 0 additions & 50 deletions MARKETING-LOG.txt

This file was deleted.

2 changes: 1 addition & 1 deletion README-DE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ System-Tray-Launcher für die drei Universal Mail Tools.
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
[![Plattform: Windows](https://img.shields.io/badge/plattform-Windows%20(System--Tray)-0078D6.svg?logo=windows&logoColor=white)](https://github.com/doc-bricks/MailProcessor)
[![GUI: PySide6 Qt](https://img.shields.io/badge/GUI-PySide6%20Qt-41CD52.svg?logo=qt&logoColor=white)](https://pypi.org/project/PySide6/)
[![Tests: 90 bestanden](https://img.shields.io/badge/tests-90%20bestanden-brightgreen.svg)](tests/)
[![Tests: 106 bestanden](https://img.shields.io/badge/tests-106%20bestanden-brightgreen.svg)](tests/)
[![Sicherheit: Richtlinie](https://img.shields.io/badge/sicherheit-SECURITY.md-blue.svg)](SECURITY.md)
[![Sicherheits-SLA: 48h Reaktion](https://img.shields.io/badge/sicherheits--SLA-48h%20Reaktion-blue.svg)](SECURITY.md)
[![Datenschutzhinweis: Entwurf](https://img.shields.io/badge/datenschutz-hinweis%20entwurf-blue.svg)](docs/PRIVACY_POLICY_DRAFT.md)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ System tray launcher for the three Universal Mail Tools.
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
[![Platform: Windows](https://img.shields.io/badge/platform-Windows%20(System%20Tray)-0078D6.svg?logo=windows&logoColor=white)](https://github.com/doc-bricks/MailProcessor)
[![GUI: PySide6 Qt](https://img.shields.io/badge/GUI-PySide6%20Qt-41CD52.svg?logo=qt&logoColor=white)](https://pypi.org/project/PySide6/)
[![Tests: 90 passed](https://img.shields.io/badge/tests-90%20passed-brightgreen.svg)](tests/)
[![Tests: 106 passed](https://img.shields.io/badge/tests-106%20passed-brightgreen.svg)](tests/)
[![Security: Policy](https://img.shields.io/badge/security-SECURITY.md-blue.svg)](SECURITY.md)
[![Security SLA: 48h Response](https://img.shields.io/badge/security%20SLA-48h%20response-blue.svg)](SECURITY.md)
[![Privacy notice: draft](https://img.shields.io/badge/privacy-notice%20draft-blue.svg)](docs/PRIVACY_POLICY_DRAFT.md)
Expand Down
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ version = "0.1.0"
description = "Local-first Windows tray launcher hub for doc-bricks Universal Mail Tools"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
license = "MIT"
license-files = ["LICENSE"]
authors = [
{name = "doc-bricks"}
]
Expand All @@ -26,12 +27,12 @@ classifiers = [
"Environment :: Win32 (MS Windows)",
"Environment :: X11 Applications :: Qt",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: MIT License",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Communications :: Email",
"Topic :: Desktop Environment",
"Topic :: Utilities",
Expand Down
37 changes: 33 additions & 4 deletions tests/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

import subprocess

try:
import tomllib
except ModuleNotFoundError:
Expand Down Expand Up @@ -38,6 +40,7 @@ def test_ci_workflow_integrity():
assert '"3.10"' in workflow_content
assert '"3.11"' in workflow_content
assert '"3.12"' in workflow_content
assert '"3.13"' in workflow_content

# Quality and test steps
assert "ruff check ." in workflow_content
Expand All @@ -46,34 +49,39 @@ def test_ci_workflow_integrity():


def test_pyproject_pep621_metadata():
"""Verify pyproject.toml PEP 621 compliance, classifiers, and ecosystem URLs."""
"""Verify pyproject.toml PEP 621/639 compliance, classifiers, and ecosystem URLs."""
raw_toml = _read_file("pyproject.toml")
data = tomllib.loads(raw_toml)

project = data.get("project", {})
assert project.get("name") == "doc-bricks-mailprocessor"
assert project.get("version") == "0.1.0"
assert project.get("license", {}).get("text") == "MIT"
assert project.get("license") == "MIT"
assert project.get("license-files") == ["LICENSE"]

classifiers = project.get("classifiers", [])
expected_classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Win32 (MS Windows)",
"Environment :: X11 Applications :: Qt",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: MIT License",
"Operating System :: Microsoft :: Windows",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Communications :: Email",
"Topic :: Desktop Environment",
"Topic :: Utilities",
]
for clf in expected_classifiers:
assert clf in classifiers, f"Classifier '{clf}' missing from pyproject.toml"

# PEP 639 rule: License string in project must not co-exist with OSI classifiers
assert "License :: OSI Approved :: MIT License" not in classifiers
assert not any(clf.startswith("License ::") for clf in classifiers)

urls = project.get("urls", {})
expected_urls = {
"Homepage": "https://github.com/doc-bricks/MailProcessor",
Expand Down Expand Up @@ -158,11 +166,32 @@ def test_gitignore_integrity():
"*.conflict",
"*-CONFLIT-*",
"LOCK*.txt",
"MARKETING-LOG.txt",
"*.receipt.json",
"dist/",
"build/",
]
for entry in required_entries:
assert entry in gitignore_content, f"Entry '{entry}' missing from .gitignore"


def test_marketing_log_not_tracked_and_policy_compliant():
"""Verify MARKETING-LOG.txt is untracked in git repository and ignored per GITHUB-POLICY."""
gitignore_content = _read_file(".gitignore")
assert "MARKETING-LOG.txt" in gitignore_content
assert "*.receipt.json" in gitignore_content

# If git is available, verify git ls-files does not track MARKETING-LOG.txt
res = subprocess.run(
["git", "ls-files", "MARKETING-LOG.txt"],
cwd=str(ROOT),
capture_output=True,
text=True,
)
if res.returncode == 0:
assert res.stdout.strip() == "", "MARKETING-LOG.txt must not be tracked in git repository"


def test_readme_bilingual_parity():
"""Verify README.md and README-DE.md cross-linking, badges, and structure."""
readme_en = _read_file("README.md")
Expand Down Expand Up @@ -196,7 +225,7 @@ def test_readme_bilingual_parity():

# Governance invariants in both
expected_invariants = [
"INV-DATA-01",
"INV-DATA-01",
"INV-NOELEV-02",
"INV-ZIPSLIP-03",
"INV-CFGISO-04",
Expand Down
Loading