From 3e268e5cf69da7799586d330896aa71859170af3 Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:29:17 +0300 Subject: [PATCH 01/10] wip --- .github/workflows/ci.yml | 46 ++++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 49 +++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b02d2ee --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: CI Checks + +on: + pull_request: + branches: [main] # Or your default branch + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Cache pip dependencies + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt # Adjust if you have dev requirements + # Install dev tools if not in requirements.txt + pip install ruff mypy pytest pytest-cov + + - name: Run Ruff (Linting & Formatting Check) + run: | + ruff check src/ tests/ + ruff format --check src/ tests/ + + - name: Run MyPy (Type Checking) + run: | + mypy src/ tests/ + + - name: Run Pytest (Tests) + run: | + pytest tests/ --cov=src --cov-report=xml --cov-report=term-missing diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..d74d291 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,49 @@ +name: Publish Python Package to PyPI + +on: + push: + tags: + - "v*.*.*" # Trigger on tags like v0.1.0, v1.2.3 + +jobs: + deploy: + runs-on: ubuntu-latest + + # Optional: Use environments for protection rules + # environment: + # name: pypi + # url: https://pypi.org/p/build-influence # Replace with your package name + + # Grant GITHUB_TOKEN permissions to authenticate with PyPI using OIDC (more secure, recommended) + permissions: + id-token: write # Required for trusted publishing + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install build dependencies + run: python -m pip install --upgrade build twine + + - name: Build package + run: python -m build + + # Preferred: Publish using Trusted Publishing (OIDC) + - name: Publish package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + # No API token needed here if PyPI project is configured for trusted publishing + + # --- Alternative: Publish using API Token (keep only ONE publish step) --- + # Uncomment the step below and comment out the Trusted Publishing step above + # if you prefer using the API token secret. + # Ensure you have configured the PYPI_API_TOKEN secret in GitHub repo settings. + # - name: Publish package to PyPI using API Token + # uses: pypa/gh-action-pypi-publish@release/v1 + # with: + # password: ${{ secrets.PYPI_API_TOKEN }} + # --------------------------------------------------------------------- From d7ee2191de9cbbb337b4e3fc07af15fd0f455d5d Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:30:08 +0300 Subject: [PATCH 02/10] wip --- CONTRIBUTING.md | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..a40f068 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,66 @@ +# Contributing to Build Influence + +First off, thank you for considering contributing to Build Influence! We welcome any help, from reporting bugs and suggesting features to submitting code changes. + +## How Can I Contribute? + +### Reporting Bugs + +- **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/drorivry/build-influence/issues). (Replace `drorivry/build-influence` with your actual repository path if different). +- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/drorivry/build-influence/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample or an executable test case** demonstrating the expected behavior that is not occurring. + +### Suggesting Enhancements + +- Open a new issue using the Feature Request template. +- Clearly describe the enhancement and the motivation for it. +- Explain why this enhancement would be useful. +- Provide code examples if applicable. + +### Pull Requests + +We actively welcome your pull requests: + +1. Fork the repo and create your branch from `main`. +2. If you've added code that should be tested, add tests. +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes (`pytest tests/`). +5. Make sure your code lints (`ruff check src/ tests/`) and is formatted (`ruff format src/ tests/`). +6. Ensure type checks pass (`mypy src/ tests/`). +7. Issue that pull request! + +## Development Setup + +1. Fork the repository on GitHub. +2. Clone your fork locally: + ```bash + git clone git@github.com:YOUR_USERNAME/build-influence.git + cd build-influence + ``` +3. Create a virtual environment (recommended): + ```bash + python3.12 -m venv venv + source venv/bin/activate # On Windows use `venv\Scripts\activate` + ``` +4. Install dependencies: + ```bash + pip install -r requirements.txt + # Install development/testing tools if they are not in requirements.txt + pip install ruff mypy pytest pytest-cov build twine + ``` + +## Coding Standards + +- Please follow the [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guide. +- Use `ruff` for linting and formatting. Our CI pipeline checks this, so please run `ruff format src/ tests/` before committing. +- Use type hints (`mypy`) for static analysis. Our CI pipeline checks this. +- Write tests using `pytest` for new functionality. + +## Code of Conduct + +Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. (Consider adding a `CODE_OF_CONDUCT.md` file). + +## Any questions? + +Feel free to open an issue if you have questions about contributing. + +Thank you for your contribution! From 04de7901100636deb20014c461b2bf7359816e90 Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:30:56 +0300 Subject: [PATCH 03/10] wip --- .github/workflows/ci.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b02d2ee..135b307 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,13 +34,9 @@ jobs: - name: Run Ruff (Linting & Formatting Check) run: | - ruff check src/ tests/ - ruff format --check src/ tests/ + ruff check src/ + ruff format --check src/ - name: Run MyPy (Type Checking) run: | - mypy src/ tests/ - - - name: Run Pytest (Tests) - run: | - pytest tests/ --cov=src --cov-report=xml --cov-report=term-missing + mypy src/ From b3cf223fe4ec1a3d2ffdacd78b675fd3183cdb39 Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:32:22 +0300 Subject: [PATCH 04/10] wip --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 135b307..d9c86be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,12 +30,12 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt # Adjust if you have dev requirements # Install dev tools if not in requirements.txt - pip install ruff mypy pytest pytest-cov + pip install black flake8 mypy pytest pytest-cov - - name: Run Ruff (Linting & Formatting Check) + - name: Run Linter and Formatter Check run: | - ruff check src/ - ruff format --check src/ + flake8 src/ tests/ + black --check src/ tests/ - name: Run MyPy (Type Checking) run: | From aa289693d88279b2998577196ee74242107e3e29 Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:32:44 +0300 Subject: [PATCH 05/10] wip --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a40f068..7c09e8b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ We actively welcome your pull requests: 2. If you've added code that should be tested, add tests. 3. If you've changed APIs, update the documentation. 4. Ensure the test suite passes (`pytest tests/`). -5. Make sure your code lints (`ruff check src/ tests/`) and is formatted (`ruff format src/ tests/`). +5. Make sure your code lints (`flake8 src/ tests/`) and is formatted (`black src/ tests/`). 6. Ensure type checks pass (`mypy src/ tests/`). 7. Issue that pull request! @@ -45,13 +45,13 @@ We actively welcome your pull requests: ```bash pip install -r requirements.txt # Install development/testing tools if they are not in requirements.txt - pip install ruff mypy pytest pytest-cov build twine + pip install black flake8 mypy pytest pytest-cov build twine ``` ## Coding Standards - Please follow the [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guide. -- Use `ruff` for linting and formatting. Our CI pipeline checks this, so please run `ruff format src/ tests/` before committing. +- Use `flake8` for linting and `black` for formatting. Our CI pipeline checks this, so please run `flake8 src/ tests/` and `black src/ tests/` before committing. - Use type hints (`mypy`) for static analysis. Our CI pipeline checks this. - Write tests using `pytest` for new functionality. From 7f7435d16d54f210109c2249901283cc0e4b5a32 Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:32:55 +0300 Subject: [PATCH 06/10] wip --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9c86be..ee0080c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,8 +34,8 @@ jobs: - name: Run Linter and Formatter Check run: | - flake8 src/ tests/ - black --check src/ tests/ + flake8 src/ + black --check src/ - name: Run MyPy (Type Checking) run: | From 66cd46718105aa996e13dba1ce57c6709ccf996b Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:41:42 +0300 Subject: [PATCH 07/10] wip --- src/build_influence/analysis/analyzer.py | 30 +++++++++++-------- src/build_influence/generation/generator.py | 8 ++--- src/build_influence/publication/__init__.py | 7 +++-- .../publication/base_publisher.py | 2 +- .../publication/linkedin_publisher.py | 2 +- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/build_influence/analysis/analyzer.py b/src/build_influence/analysis/analyzer.py index 26e5f22..00a012f 100644 --- a/src/build_influence/analysis/analyzer.py +++ b/src/build_influence/analysis/analyzer.py @@ -1,6 +1,6 @@ import subprocess from pathlib import Path -from typing import List, Dict, Any +from typing import List, Dict, Any, Optional import litellm import json from tqdm import tqdm @@ -128,7 +128,7 @@ def analyze(self) -> Dict[str, Any]: # -------------------------------------------- # --- Final Result --- - final_analysis_result = { + final_analysis_result: Dict[str, Any] = { **interim_result, "high_level_features": high_level_features, } @@ -185,7 +185,7 @@ def _extract_metadata(self) -> Dict[str, Any]: def _build_file_tree(self) -> List[Dict[str, Any]]: """Scan directory structure and build a list of files to consider.""" logger.debug("Building file tree...") - file_tree = [] + file_tree: List[Dict[str, Any]] = [] potential_files_count = 0 try: @@ -196,7 +196,7 @@ def _build_file_tree(self) -> List[Dict[str, Any]]: try: relative_path = item.relative_to(self.repo_path) - file_info = { + file_info: Dict[str, Any] = { "path": str(relative_path), "absolute_path": str(item), "size": item.stat().st_size, @@ -269,7 +269,7 @@ def _analyze_file_content_with_ai( Generic helper to analyze file content using LiteLLM with a specific prompt. """ - insights = {"error": None} + insights: Dict[str, Any] = {"error": None} file_name = file_path.name try: @@ -406,15 +406,17 @@ def _analyze_code_file_with_ai(self, file_path: Path) -> Dict[str, Any]: # logger.debug( # f"Attempting code key extraction from: {raw_insights!r}" # ) - purpose = raw_insights.get("purpose") + purpose: Optional[str] = raw_insights.get("purpose") # logger.debug(f"Code Purpose extracted: {purpose!r}") - elements = raw_insights.get("key_elements", []) + elements: Optional[List[str]] = raw_insights.get("key_elements", []) # logger.debug(f"Code Elements extracted: {elements!r}") - dependencies = raw_insights.get("dependencies", []) + dependencies: Optional[List[str]] = raw_insights.get("dependencies", []) # logger.debug( # f"Code Dependencies extracted: {dependencies!r}" # ) - aspects = raw_insights.get("interesting_aspects", []) + aspects: Optional[List[str]] = raw_insights.get( + "interesting_aspects", [] + ) # logger.debug(f"Code Aspects extracted: {aspects!r}") # --- End Detailed Logging --- @@ -456,10 +458,12 @@ def _analyze_doc_file_with_ai(self, file_path: Path) -> Dict[str, Any]: return raw_insights # Return error dict as is elif isinstance(raw_insights, dict): try: - summary = raw_insights.get("summary") - features = raw_insights.get("features", []) - setup_steps = raw_insights.get("setup_steps", []) - usage_examples = raw_insights.get("usage_examples", []) + summary: Optional[str] = raw_insights.get("summary") + features: Optional[List[str]] = raw_insights.get("features", []) + setup_steps: Optional[List[str]] = raw_insights.get("setup_steps", []) + usage_examples: Optional[List[str]] = raw_insights.get( + "usage_examples", [] + ) return { "summary": summary, diff --git a/src/build_influence/generation/generator.py b/src/build_influence/generation/generator.py index 1fe39fc..a9f07e3 100644 --- a/src/build_influence/generation/generator.py +++ b/src/build_influence/generation/generator.py @@ -85,13 +85,13 @@ def _build_prompt( **Instructions:** 1. Synthesize the provided information. 2. Write a compelling '{content_type}' post in well-formatted Markdown. - 3. Ensure the tone is appropriate for the target audience and platform + 3. Ensure the tone is appropriate for the target audience and platform (general technical audience for Markdown). - 4. If generating a 'deepdive', elaborate on technical aspects. If + 4. If generating a 'deepdive', elaborate on technical aspects. If 'announcement', focus on highlights and purpose. - 5. Make sure the output is only the Markdown content, without any preamble + 5. Make sure the output is only the Markdown content, without any preamble or explanation. - + **Generated Markdown Post:** """.strip() diff --git a/src/build_influence/publication/__init__.py b/src/build_influence/publication/__init__.py index 9b2eb55..e63f80f 100644 --- a/src/build_influence/publication/__init__.py +++ b/src/build_influence/publication/__init__.py @@ -1,5 +1,7 @@ # Publication module +from typing import Type + from .base_publisher import BasePublisher, PublicationContent, PublishResult from .linkedin_publisher import LinkedInPublisher from .devto_publisher import DevToPublisher @@ -17,14 +19,15 @@ def get_publisher(platform_name: str) -> BasePublisher | None: """Factory function to get a publisher instance for the platform name.""" - publisher_class = _publisher_map.get(platform_name.lower()) + publisher_class: Type[BasePublisher] | None = _publisher_map.get( + platform_name.lower() + ) if publisher_class: return publisher_class() return None __all__ = [ - "BasePublisher", "PublicationContent", "PublishResult", "LinkedInPublisher", diff --git a/src/build_influence/publication/base_publisher.py b/src/build_influence/publication/base_publisher.py index fa3d040..67c1184 100644 --- a/src/build_influence/publication/base_publisher.py +++ b/src/build_influence/publication/base_publisher.py @@ -24,7 +24,7 @@ class BasePublisher(ABC): platform_name: str = "Base" @abstractmethod - async def publish(self, content: PublicationContent, config: dict) -> PublishResult: + def publish(self, content: PublicationContent, config: dict) -> PublishResult: """ Publishes the given content to the specific platform. diff --git a/src/build_influence/publication/linkedin_publisher.py b/src/build_influence/publication/linkedin_publisher.py index d268b3e..d47852c 100644 --- a/src/build_influence/publication/linkedin_publisher.py +++ b/src/build_influence/publication/linkedin_publisher.py @@ -6,7 +6,7 @@ class LinkedInPublisher(BasePublisher): platform_name = "LinkedIn" - async def publish(self, content: PublicationContent, config: dict) -> PublishResult: + def publish(self, content: PublicationContent, config: dict) -> PublishResult: """Publishes content to LinkedIn. Placeholder implementation.""" print(f"Publishing to {self.platform_name}:") print(f"Title: {content.title}") From 950b7354d431af13419e9d8f546b9b920d450c5a Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:42:56 +0300 Subject: [PATCH 08/10] wip --- src/build_influence/generation/linkedin_generator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/build_influence/generation/linkedin_generator.py b/src/build_influence/generation/linkedin_generator.py index b33c10a..c988b5b 100644 --- a/src/build_influence/generation/linkedin_generator.py +++ b/src/build_influence/generation/linkedin_generator.py @@ -76,8 +76,8 @@ def _build_prompt( 2. Focus on the value proposition, achievements, or key learnings. 3. Maintain a professional and engaging tone suitable for LinkedIn. 4. Use appropriate formatting (bullet points, maybe bolding key terms). -5. If '{content_type}' is 'announcement', highlight the launch/update - professionally. If 'deepdive', focus on technical achievements or +5. If '{content_type}' is 'announcement', highlight the launch/update + professionally. If 'deepdive', focus on technical achievements or learnings. 6. Consider adding relevant professional hashtags (e.g., #SoftwareDevelopment, #Tech, #ProjectManagement). From 15338013a72c03f503c52111cd1ef9b42529d1f8 Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:43:13 +0300 Subject: [PATCH 09/10] wip --- src/build_influence/analysis/analyzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build_influence/analysis/analyzer.py b/src/build_influence/analysis/analyzer.py index 00a012f..32ddc86 100644 --- a/src/build_influence/analysis/analyzer.py +++ b/src/build_influence/analysis/analyzer.py @@ -510,7 +510,7 @@ def _analyze_doc_file_with_ai(self, file_path: Path) -> Dict[str, Any]: # Print first few files with AI insights if available for i, file_info in enumerate(result["file_tree"][:5]): print( - f"\n File {i+1}: {file_info['path']} " + f"\n File {i + 1}: {file_info['path']} " f"({file_info['type']}, {file_info['size']}b)" ) insights = None From 84002ad2a5d042175c68e2383c9b09dfcf5e1881 Mon Sep 17 00:00:00 2001 From: Dror Ivry Date: Sat, 3 May 2025 19:44:58 +0300 Subject: [PATCH 10/10] wip --- .github/workflows/ci.yml | 4 ++-- CONTRIBUTING.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee0080c..e8e5fde 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,8 +29,8 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt # Adjust if you have dev requirements - # Install dev tools if not in requirements.txt - pip install black flake8 mypy pytest pytest-cov + # Install dev tools and type stubs if not in requirements.txt + pip install black flake8 mypy pytest pytest-cov types-tqdm types-PyYAML - name: Run Linter and Formatter Check run: | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c09e8b..e6ce05f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -44,8 +44,8 @@ We actively welcome your pull requests: 4. Install dependencies: ```bash pip install -r requirements.txt - # Install development/testing tools if they are not in requirements.txt - pip install black flake8 mypy pytest pytest-cov build twine + # Install development/testing tools and type stubs if they are not in requirements.txt + pip install black flake8 mypy pytest pytest-cov build twine types-tqdm types-PyYAML ``` ## Coding Standards