diff --git a/src/auto_readme/github/__init__.py b/src/auto_readme/github/__init__.py new file mode 100644 index 0000000..c7cafbf --- /dev/null +++ b/src/auto_readme/github/__init__.py @@ -0,0 +1,128 @@ +"""GitHub Actions integration for README auto-update workflows.""" + +from pathlib import Path +from typing import Optional + +from ..models import Project + + +class GitHubActionsGenerator: + """Generates GitHub Actions workflows for README updates.""" + + WORKFLOW_TEMPLATE = """name: Auto Update README + +on: + push: + branches: [main, master] + paths: + - '**.py' + - '**.js' + - '**.ts' + - '**.go' + - '**.rs' + - 'package.json' + - 'pyproject.toml' + - 'go.mod' + - 'Cargo.toml' + - 'requirements.txt' + workflow_dispatch: + inputs: + force: + description: 'Force README regeneration' + required: false + default: 'false' + +jobs: + update-readme: + runs-on: ubuntu-latest + if: github.repository_owner != '{{ owner }}' || github.event_name == 'workflow_dispatch' + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install auto-readme + run: | + pip install --upgrade pip + pip install auto-readme-cli + + - name: Generate README + run: | + auto-readme generate --input . --output README.md --force + + - name: Commit and push changes + if: github.event_name != 'workflow_dispatch' || github.event.inputs.force == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add README.md + git diff --quiet README.md || git commit -m "docs: Auto-update README" + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +""" + + @classmethod + def can_generate(cls, project: Project) -> bool: + """Check if GitHub Actions integration can be generated.""" + return ( + project.git_info is not None + and project.git_info.is_repo + and project.git_info.owner is not None + ) + + @classmethod + def generate_workflow(cls, project: Project, output_path: Optional[Path] = None) -> str: + """Generate the GitHub Actions workflow content.""" + owner = project.git_info.owner if project.git_info else "owner" + workflow_content = cls.WORKFLOW_TEMPLATE.replace("{{ owner }}", owner) + return workflow_content + + @classmethod + def save_workflow(cls, project: Project, output_dir: Path) -> Path: + """Save the GitHub Actions workflow to a file.""" + workflow_content = cls.generate_workflow(project) + workflow_path = output_dir / ".github" / "workflows" / "readme-update.yml" + workflow_path.parent.mkdir(parents=True, exist_ok=True) + workflow_path.write_text(workflow_content) + return workflow_path + + +class GitHubRepoDetector: + """Detects GitHub repository information.""" + + @staticmethod + def is_github_repo(remote_url: Optional[str]) -> bool: + """Check if the remote URL is a GitHub repository.""" + if not remote_url: + return False + return "github.com" in remote_url.lower() + + @staticmethod + def extract_repo_info(remote_url: Optional[str]) -> tuple[Optional[str], Optional[str]]: + """Extract owner and repo name from remote URL.""" + if not remote_url: + return None, None + + import re + + patterns = [ + r"github\.com[:/](/[^/]+)/([^/]+)\.git", + r"github\.com/([^/]+)/([^/]+)", + r"git@github\.com:([^/]+)/([^/]+)\.git", + r"git@github\.com:([^/]+)/([^/]+)", + ] + + for pattern in patterns: + match = re.search(pattern, remote_url) + if match: + owner, repo = match.groups() + repo = repo.replace(".git", "") + return owner, repo + + return None, None