diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8515b87..a57aff0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -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 @@ -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 diff --git a/.gitignore b/.gitignore index a42a9bd..0ce0676 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index 50d11d4..c7aca7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/MARKETING-LOG.txt b/MARKETING-LOG.txt deleted file mode 100644 index c8fd1e9..0000000 --- a/MARKETING-LOG.txt +++ /dev/null @@ -1,50 +0,0 @@ -# MARKETING-LOG.txt — MailProcessor Discoverability & Visibility Recommendations - -Date: 2026-07-27 -Repository: doc-bricks/MailProcessor -Path: Path B (Discoverability, Projektauftritt, Nutzerführung & Sichtbarkeit) - ---- - -## Non-Automated Marketing Recommendations - -1. **Video Walkthrough / GIF Recording**: - - Record a 30-second GIF or short video showing how MailProcessor operates in the Windows system tray (right-click menu, launching Mail Cleaner / Docs Grabber / Invoice Mail with 1 click). - - Embed this GIF at the top of `README.md` and `README-DE.md`. - -2. **Windows Store & WinGet Packaging**: - - Package `MailProcessor-0.1.0-desktop.exe` for WinGet (`winget install doc-bricks.MailProcessor`) and Microsoft Store to reach Windows desktop users directly. - -3. **Product Hunt & Reddit Showcases**: - - Post a showcase on r/selfhosted, r/windows, and Product Hunt highlighting privacy-first local IMAP mail management without cloud subscription fees. - -4. **Integration with open-bricks & Ecosystem Navigation**: - - Cross-link MailProcessor on the `open-bricks` portal landing page as the central desktop hub for the `doc-bricks` mail tools suite. - ---- - -## Path B Review (2026-09-10) — Pfad B Marketing & Discoverability Audit - -Status: COMPLETED (Bilingual Parity, Dual Mermaid Diagrams, Governance Invariants, Enhanced Badges) -Auditor: Gemini (Antigravity Agent) -Test Suite: 79/79 passing - -### Completed Automated Upgrades: -- Upgraded `README.md` and `README-DE.md` to dual-Mermaid architecture: - - System architecture flowchart (`flowchart TD`) - - Execution lifecycle sequence diagram (`sequenceDiagram` with `autonumber`) - - Full compliance with `HOOK-BANNER-ASSET-01` (all node/edge labels strictly quoted). -- Added quick navigation / table of contents and bilingual switchers. -- Formalized 8 Governance & Runtime Invariants (`INV-LOCAL-01` to `INV-SLA-08`). -- Expanded Shields.io badges (Windows System Tray, PySide6 Qt GUI, 100% Local-First privacy, 48h security SLA, ruff code style). -- Added cross-ecosystem matrix linking all doc-bricks sibling tools and open-bricks umbrella. -- Added contract tests in `tests/test_metadata.py` ensuring long-term architectural regression safety. -- Bumped `llms.txt` to 2026-09-10 with documented invariants and diagram structures. - -### Non-Automated Marketing Recommendations for User / Admin: -1. **GitHub Social Preview & OpenGraph Card**: - - The repository currently uses the default GitHub card. Upload `assets/banner.png` (or 1280x640 social preview) into Repo Settings -> General -> Social Preview. -2. **WinGet Manifest Submission**: - - Create a winget package manifest for `doc-bricks.MailProcessor` under `microsoft/winget-pkgs` for seamless `winget install doc-bricks.MailProcessor`. -3. **Short GIF Demo / Video Clip**: - - Record an animated GIF showing: launch from Windows tray -> right click -> 1-click launch of Universal Mail Cleaner or Docs Grabber. diff --git a/README-DE.md b/README-DE.md index 6e91350..20d78bd 100644 --- a/README-DE.md +++ b/README-DE.md @@ -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) diff --git a/README.md b/README.md index 815788a..da3ecea 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/pyproject.toml b/pyproject.toml index 4824497..63eecac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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"} ] @@ -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", diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 0874b3f..6aee0b2 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -2,6 +2,8 @@ from __future__ import annotations +import subprocess + try: import tomllib except ModuleNotFoundError: @@ -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 @@ -46,14 +49,15 @@ 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 = [ @@ -61,12 +65,12 @@ def test_pyproject_pep621_metadata(): "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", @@ -74,6 +78,10 @@ def test_pyproject_pep621_metadata(): 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", @@ -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") @@ -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",