diff --git a/.github/workflows/postsubmit-cpp.yml b/.github/workflows/code-health-cpp.yml similarity index 97% rename from .github/workflows/postsubmit-cpp.yml rename to .github/workflows/code-health-cpp.yml index 6e3b049..0017cf9 100644 --- a/.github/workflows/postsubmit-cpp.yml +++ b/.github/workflows/code-health-cpp.yml @@ -1,5 +1,5 @@ --- -name: Postsubmit (C++) +name: Code Health (C++) on: # yamllint disable-line rule:truthy push: diff --git a/.github/workflows/postsubmit-py.yml b/.github/workflows/code-health-py.yml similarity index 96% rename from .github/workflows/postsubmit-py.yml rename to .github/workflows/code-health-py.yml index 0c2e77e..4bb5a1b 100644 --- a/.github/workflows/postsubmit-py.yml +++ b/.github/workflows/code-health-py.yml @@ -1,5 +1,5 @@ --- -name: Postsubmit (Python) +name: Code Health (Python) on: # yamllint disable-line rule:truthy push: diff --git a/.github/workflows/presubmit-cpp.yml b/.github/workflows/presubmit-cpp.yml index 53c8af3..ae7b7ae 100644 --- a/.github/workflows/presubmit-cpp.yml +++ b/.github/workflows/presubmit-cpp.yml @@ -41,8 +41,12 @@ jobs: CHANGED_CPP_FILES=$(echo "$CHANGED_FILES" | \ grep -E '\.(cc|cpp|cxx|c\+\+|h|hpp|hxx|h\+\+)$' || true) + # Filter for C++ files specifically in the problems directory + CHANGED_CPP_PROBLEMS_FILES=$(echo "$CHANGED_CPP_FILES" | \ + grep -E '^problems/' || true) + # Extract unique problem directories from changed C++ files - CHANGED_PROBLEMS=$(echo "$CHANGED_CPP_FILES" | \ + CHANGED_PROBLEMS=$(echo "$CHANGED_CPP_PROBLEMS_FILES" | \ grep -E '^problems/[^/]+/' | cut -d'/' -f2 | \ sort -u | tr '\n' ' ' || true) @@ -57,13 +61,15 @@ jobs: echo "Changed C++ files:" echo "$CHANGED_CPP_FILES" + echo "Changed C++ files in problems/:" + echo "$CHANGED_CPP_PROBLEMS_FILES" echo "Changed problems: $CHANGED_PROBLEMS" echo "C++ config changes: $CPP_CONFIG_CHANGES" echo "Common directory changes: $COMMON_CHANGES" # Set outputs echo "changed_problems=$CHANGED_PROBLEMS" >> $GITHUB_OUTPUT - echo "has_cpp_changes=$([ -n "$CHANGED_CPP_FILES" ] && \ + echo "has_cpp_changes=$([ -n "$CHANGED_CPP_PROBLEMS_FILES" ] && \ echo 'true' || echo 'false')" >> $GITHUB_OUTPUT echo "has_cpp_config_changes=$([ -n "$CPP_CONFIG_CHANGES" ] && \ echo 'true' || echo 'false')" >> $GITHUB_OUTPUT @@ -137,7 +143,7 @@ jobs: "false" ] && \ [ "${{ steps.detect-changes.outputs.has_common_changes }}" = \ "false" ]; then - echo "- No C++ files changed - skipped all tasks" >> \ + echo "- No C++ files in problems/ changed - skipped all tasks" >> \ $GITHUB_STEP_SUMMARY elif [ "${{ steps.detect-changes.outputs.should_run_all_tests }}" = \ "true" ]; then diff --git a/.github/workflows/presubmit-python.yml b/.github/workflows/presubmit-python.yml index eff4e9a..59b8af6 100644 --- a/.github/workflows/presubmit-python.yml +++ b/.github/workflows/presubmit-python.yml @@ -44,8 +44,12 @@ jobs: CHANGED_PYTHON_FILES=$(echo "$CHANGED_FILES" | \ grep '\.py$' || true) + # Filter for Python files specifically in the problems directory + CHANGED_PYTHON_PROBLEMS_FILES=$(echo "$CHANGED_PYTHON_FILES" | \ + grep -E '^problems/' || true) + # Extract unique problem directories from changed Python files - CHANGED_PROBLEMS=$(echo "$CHANGED_PYTHON_FILES" | \ + CHANGED_PROBLEMS=$(echo "$CHANGED_PYTHON_PROBLEMS_FILES" | \ grep -E '^problems/[^/]+/' | cut -d'/' -f2 | \ sort -u | tr '\n' ' ' || true) @@ -55,12 +59,14 @@ jobs: echo "Changed Python files:" echo "$CHANGED_PYTHON_FILES" + echo "Changed Python files in problems/:" + echo "$CHANGED_PYTHON_PROBLEMS_FILES" echo "Changed problems: $CHANGED_PROBLEMS" echo "Python config changes: $PYTHON_CONFIG_CHANGES" # Set outputs echo "changed_problems=$CHANGED_PROBLEMS" >> $GITHUB_OUTPUT - echo "has_python_changes=$([ -n "$CHANGED_PYTHON_FILES" ] && \ + echo "has_python_changes=$([ -n "$CHANGED_PYTHON_PROBLEMS_FILES" ] && \ echo 'true' || echo 'false')" >> $GITHUB_OUTPUT echo "has_python_config_changes=$([ -n "$PYTHON_CONFIG_CHANGES" ] && \ echo 'true' || echo 'false')" >> $GITHUB_OUTPUT @@ -118,7 +124,7 @@ jobs: "false" ] && \ [ "${{ steps.detect-changes.outputs.has_python_config_changes }}" \ = "false" ]; then - echo "- No Python files changed - skipped all tasks" >> \ + echo "- No Python files in problems/ changed - skipped all tasks" >> \ $GITHUB_STEP_SUMMARY elif [ "${{ steps.detect-changes.outputs.should_run_all_tests }}" = \ "true" ]; then diff --git a/.github/workflows/update-badges.yml b/.github/workflows/update-badges.yml new file mode 100644 index 0000000..8aa46d1 --- /dev/null +++ b/.github/workflows/update-badges.yml @@ -0,0 +1,43 @@ +--- +name: Update Badges + +on: # yamllint disable-line rule:truthy + push: + branches: ["main"] + workflow_dispatch: # Allow manual triggering + +jobs: + update-badges: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Update badges + run: | + python3 scripts/update_badges.py + + - name: Check for changes + id: verify-changed-files + run: | + if git diff --quiet; then + echo "changed=false" >> $GITHUB_OUTPUT + else + echo "changed=true" >> $GITHUB_OUTPUT + fi + + - name: Commit changes + if: steps.verify-changed-files.outputs.changed == 'true' + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add README.md + git commit -m "docs: update problem count badges [skip ci]" + git push diff --git a/Makefile b/Makefile index d324fd5..f13346a 100644 --- a/Makefile +++ b/Makefile @@ -263,6 +263,12 @@ stats: @echo "Available problems:" @for prob in $(SNAKE_CASE_PROBLEM_NAMES); do echo " $(call color_cyan,- $$prob)"; done +# Update README badges with current problem counts +.PHONY: update-badges +update-badges: + @echo "$(call color_green,Updating README badges...)" + @./scripts/update_badges.sh + # Debug Google Test configuration .PHONY: debug-gtest debug-gtest: @@ -329,6 +335,7 @@ help: @echo "$(call color_yellow,Utility Targets:)" @echo " clean - Clean build artifacts" @echo " stats - Show project statistics" + @echo " update-badges - Update README badges with current problem counts" @echo " debug-gtest - Debug Google Test configuration" @echo " help - Show this help message" @echo "" diff --git a/README.md b/README.md index 8b30a5a..133757d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,24 @@ -# Leetcode +# 🧮 LeetCode Solutions -[![Code Health (C++)](https://github.com/mathusanm6/LeetCode/actions/workflows/postsubmit-cpp.yml/badge.svg)](https://github.com/mathusanm6/LeetCode/actions/workflows/postsubmit-cpp.yml) -[![C++ Linter](https://github.com/mathusanm6/LeetCode/actions/workflows/linter-cpp.yml/badge.svg)](https://github.com/mathusanm6/LeetCode/actions/workflows/linter-cpp.yml) +
-[![Code Health (Python)](https://github.com/mathusanm6/LeetCode/actions/workflows/postsubmit-py.yml/badge.svg)](https://github.com/mathusanm6/LeetCode/actions/workflows/postsubmit-py.yml) -[![Python Linter](https://github.com/mathusanm6/LeetCode/actions/workflows/linter-py.yml/badge.svg)](https://github.com/mathusanm6/LeetCode/actions/workflows/linter-py.yml) +### 🔬 Code Health & Testing + +[![C++ Tests](https://img.shields.io/github/actions/workflow/status/mathusanm6/LeetCode/code-health-cpp.yml?branch=main&label=C%2B%2B%20Tests&logo=cplusplus&logoColor=white&style=for-the-badge)](https://github.com/mathusanm6/LeetCode/actions/workflows/code-health-cpp.yml) +[![Python Tests](https://img.shields.io/github/actions/workflow/status/mathusanm6/LeetCode/code-health-py.yml?branch=main&label=Python%20Tests&logo=python&logoColor=white&style=for-the-badge)](https://github.com/mathusanm6/LeetCode/actions/workflows/code-health-py.yml) + +### 🔍 Code Quality & Linting + +[![C++ Linter](https://img.shields.io/github/actions/workflow/status/mathusanm6/LeetCode/linter-cpp.yml?branch=main&label=C%2B%2B%20Linter&logo=cplusplus&logoColor=white&style=for-the-badge&color=blue)](https://github.com/mathusanm6/LeetCode/actions/workflows/linter-cpp.yml) +[![Python Linter](https://img.shields.io/github/actions/workflow/status/mathusanm6/LeetCode/linter-py.yml?branch=main&label=Python%20Linter&logo=python&logoColor=white&style=for-the-badge&color=blue)](https://github.com/mathusanm6/LeetCode/actions/workflows/linter-py.yml) + +### 📊 Repository Stats + +[![Last Commit](https://img.shields.io/github/last-commit/mathusanm6/LeetCode?style=for-the-badge&logo=git&logoColor=white)](https://github.com/mathusanm6/LeetCode/commits/main) +[![C++ Solutions](https://img.shields.io/badge/C%2B%2B%20Solutions-2-blue?style=for-the-badge&logo=cplusplus&logoColor=white)](https://github.com/mathusanm6/LeetCode/tree/main/problems) +[![Python Solutions](https://img.shields.io/badge/Python%20Solutions-2-green?style=for-the-badge&logo=python&logoColor=white)](https://github.com/mathusanm6/LeetCode/tree/main/problems) + +
## Description diff --git a/scripts/update_badges.py b/scripts/update_badges.py new file mode 100644 index 0000000..1d6ba85 --- /dev/null +++ b/scripts/update_badges.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +""" +Script to automatically update README badges with current problem counts. +This script counts the number of solved problems in each language and updates the README.md file. +""" + +import os +import re +from pathlib import Path + + +def count_cpp_problems(): + """Count C++ problems in the problems directory.""" + problems_dir = Path("problems") + if not problems_dir.exists(): + return 0 + + cpp_count = 0 + for problem_dir in problems_dir.iterdir(): + if problem_dir.is_dir(): + # Check if this problem has C++ files + cpp_files = list(problem_dir.glob("*.cc")) + list(problem_dir.glob("*.cpp")) + if cpp_files: + cpp_count += 1 + + return cpp_count + + +def count_python_problems(): + """Count Python problems in the problems directory.""" + problems_dir = Path("problems") + if not problems_dir.exists(): + return 0 + + python_count = 0 + for problem_dir in problems_dir.iterdir(): + if problem_dir.is_dir(): + # Check if this problem has Python files + python_files = list(problem_dir.glob("*.py")) + if python_files: + python_count += 1 + + return python_count + + +def update_readme_badges(cpp_count, python_count): + """Update the README.md file with new badge counts.""" + readme_path = Path("README.md") + if not readme_path.exists(): + print("ERROR: README.md not found!") + return False + + # Read the current README content + with open(readme_path, "r", encoding="utf-8") as f: + content = f.read() + + # Define the new badge lines + cpp_badge = f"[![C++ Solutions](https://img.shields.io/badge/C%2B%2B%20Solutions-{cpp_count}-blue?style=for-the-badge&logo=cplusplus&logoColor=white)](https://github.com/mathusanm6/LeetCode/tree/main/problems)" + python_badge = f"[![Python Solutions](https://img.shields.io/badge/Python%20Solutions-{python_count}-green?style=for-the-badge&logo=python&logoColor=white)](https://github.com/mathusanm6/LeetCode/tree/main/problems)" + + # Update C++ badge + cpp_pattern = r"\[\!\[C\+\+ Solutions\].*?\)\]\(.*?\)" + if re.search(cpp_pattern, content): + content = re.sub(cpp_pattern, cpp_badge, content) + else: + print("WARNING: C++ badge pattern not found in README.md") + + # Update Python badge + python_pattern = r"\[\!\[Python Solutions\].*?\)\]\(.*?\)" + if re.search(python_pattern, content): + content = re.sub(python_pattern, python_badge, content) + else: + print("WARNING: Python badge pattern not found in README.md") + + # Write the updated content back + with open(readme_path, "w", encoding="utf-8") as f: + f.write(content) + + return True + + +def main(): + """Main function to count problems and update badges.""" + print("🔍 Counting solved problems...") + + # Count problems in each language + cpp_count = count_cpp_problems() + python_count = count_python_problems() + + print(f"📊 Found {cpp_count} C++ problems") + print(f"📊 Found {python_count} Python problems") + + # Update the README + if update_readme_badges(cpp_count, python_count): + print("✅ README.md badges updated successfully!") + print(f" C++ Solutions: {cpp_count}") + print(f" Python Solutions: {python_count}") + else: + print("❌ Failed to update README.md") + return 1 + + return 0 + + +if __name__ == "__main__": + # Change to the repository root directory + script_dir = Path(__file__).parent + repo_root = script_dir.parent + os.chdir(repo_root) + + exit(main()) diff --git a/scripts/update_badges.sh b/scripts/update_badges.sh new file mode 100755 index 0000000..3669ec3 --- /dev/null +++ b/scripts/update_badges.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# Update README badges with current problem counts + +set -e + +# Get the directory of this script +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(dirname "$SCRIPT_DIR")" + +# Change to repository root +cd "$REPO_ROOT" + +# Run the Python script +python3 scripts/update_badges.py