From 6c8126853f42db25540c6197bc0c0103d7d0c1f4 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 06:38:22 +0000 Subject: [PATCH 1/2] feat: autonomous repository management and governance Introduces a comprehensive suite of tools and GitHub Actions to automate repository maintenance, CI, code quality, security, and contributor engagement. - Added community health files (`CODE_OF_CONDUCT.md`, `CONTRIBUTING.md`, issue/PR templates). - Created `greetings.yml` for new contributors. - Created `stale.yml` for automated issue management. - Set up `ci.yml` for Python and Node.js testing. - Created `ai-review.yml` for automated PR reviews using CodeRabbit. - Implemented `repo-maintenance.yml` to automatically generate architecture diagrams, an SBOM, and sync documentation. - Added custom Python tools (`docs_sync.py`, `generate_knowledge_graph.py`) to build dynamic knowledge graphs and markdown indices. Co-authored-by: NITISH-R-G <225521762+NITISH-R-G@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/issue_template.md | 32 ++++++++++ .github/pull_request_template.md | 22 +++++++ .github/workflows/ai-review.yml | 18 ++++++ .github/workflows/ci.yml | 43 +++++++++++++ .github/workflows/greetings.yml | 31 ++++++++++ .github/workflows/pages.yml | 35 +++++++++++ .github/workflows/repo-maintenance.yml | 56 +++++++++++++++++ .github/workflows/stale.yml | 20 ++++++ CODE_OF_CONDUCT.md | 27 +++++++++ CONTRIBUTING.md | 25 ++++++++ tools/docs_sync.py | 24 ++++++++ tools/generate_knowledge_graph.py | 77 ++++++++++++++++++++++++ 12 files changed, 410 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/issue_template.md create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/ai-review.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/greetings.yml create mode 100644 .github/workflows/pages.yml create mode 100644 .github/workflows/repo-maintenance.yml create mode 100644 .github/workflows/stale.yml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 tools/docs_sync.py create mode 100644 tools/generate_knowledge_graph.py diff --git a/.github/ISSUE_TEMPLATE/issue_template.md b/.github/ISSUE_TEMPLATE/issue_template.md new file mode 100644 index 0000000..d3e9a66 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue_template.md @@ -0,0 +1,32 @@ +--- +name: Issue Report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug or feature request** +A clear and concise description of what the bug is or what the feature request is about. + +**To Reproduce** +Steps to reproduce the behavior (if applicable): +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..411e9fd --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Description +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. + +Fixes # (issue) + +## Type of change +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +## How Has This Been Tested? +Please describe the tests that you ran to verify your changes. + +## Checklist: +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes diff --git a/.github/workflows/ai-review.yml b/.github/workflows/ai-review.yml new file mode 100644 index 0000000..3a03f1d --- /dev/null +++ b/.github/workflows/ai-review.yml @@ -0,0 +1,18 @@ +name: AI Code Review + +on: + pull_request: + types: [opened, synchronize] + +jobs: + review: + runs-on: ubuntu-latest + steps: + - uses: coderabbitai/openai-pr-reviewer@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + with: + debug: false + review_simple_changes: false + review_comment_lgtm: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d99ebf9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,43 @@ +name: CI + +on: + push: + branches: [ "main", "master" ] + pull_request: + branches: [ "main", "master" ] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + cache: 'pip' + + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + + - name: Install dependencies + run: | + $HOME/.cargo/bin/uv venv + $HOME/.cargo/bin/uv pip install -e ".[dev]" + + - name: Run Python tests + run: $HOME/.cargo/bin/uv run pytest tests/ + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install Frontend dependencies + run: cd web && npm install + + - name: Run Frontend tests + run: cd web && npm run build diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yml new file mode 100644 index 0000000..3de6e67 --- /dev/null +++ b/.github/workflows/greetings.yml @@ -0,0 +1,31 @@ +name: Greetings + +on: + issues: + types: [opened] + pull_request: + types: [opened] + +jobs: + welcome: + runs-on: ubuntu-latest + steps: + - uses: actions/github-script@v6 + with: + script: | + const isPR = !!context.payload.pull_request; + const user = context.payload.sender.login; + const authorAssociation = context.payload.issue?.author_association || context.payload.pull_request?.author_association; + + if (authorAssociation === 'FIRST_TIMER' || authorAssociation === 'FIRST_TIME_CONTRIBUTOR') { + const body = isPR + ? `Welcome @${user}! Thank you for your first pull request. A maintainer will review it shortly. Please ensure all tests pass and your code follows our contribution guidelines.` + : `Welcome @${user}! Thank you for opening your first issue. We will look into it as soon as possible.`; + + github.rest.issues.createComment({ + issue_number: context.issue.number || context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }); + } diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..ef860cb --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,35 @@ +name: Deploy documentation to GitHub Pages + +on: + push: + branches: ["main"] + + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Pages + uses: actions/configure-pages@v5 + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: './docs' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/repo-maintenance.yml b/.github/workflows/repo-maintenance.yml new file mode 100644 index 0000000..3699a4f --- /dev/null +++ b/.github/workflows/repo-maintenance.yml @@ -0,0 +1,56 @@ +name: Repository Maintenance + +on: + push: + branches: [ "main", "master" ] + pull_request: + branches: [ "main", "master" ] + +permissions: + contents: write + +jobs: + maintenance: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref || github.ref }} + lfs: true + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + $HOME/.cargo/bin/uv venv + $HOME/.cargo/bin/uv pip install --system pydeps xdg-utils cyclonedx-bom ruff + + - name: Run Ruff autofix + run: ruff check --fix . || true + + - name: Generate Knowledge Graph + run: python tools/generate_knowledge_graph.py + + - name: Sync Docs + run: python tools/docs_sync.py + + - name: Generate Architecture Diagram + run: pydeps . -o docs/arch.svg || true + + - name: Generate SBOM + run: | + $HOME/.cargo/bin/uv venv + $HOME/.cargo/bin/uv pip install -e ".[dev]" + $HOME/.cargo/bin/uv run cyclonedx-py environment -o bom.json || true + + - name: Commit changes + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add docs/ bom.json || true + git commit -m "Auto-generated repository artifacts" || true + git push || true diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..db3b015 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,20 @@ +name: Manage Stale Issues + +on: + schedule: + - cron: "0 0 * * *" + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' + stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' + days-before-stale: 60 + days-before-close: 7 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6b83cee --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,27 @@ +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e462d0b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,25 @@ +# Contributing + +First off, thank you for considering contributing to this project. It's people like you that make open source such a great community. + +## Where do I go from here? + +If you've noticed a bug or have a feature request, make sure to check our Issues to see if someone else in the community has already created a ticket. If not, go ahead and make one! + +## Fork & create a branch + +If this is something you think you can fix, then fork the repository and create a branch with a descriptive name. + +## Implement your fix or feature + +At this point, you're ready to make your changes! Feel free to ask for help; everyone is a beginner at first. + +## Make a Pull Request + +At this point, you should switch back to your master branch and make sure it's up to date with the main project's master branch. +Then run `uv run pytest tests/` and `cd web && npm test` to ensure tests are passing. +Once tests pass, open a Pull Request. + +## Keeping your Pull Request updated + +If a maintainer asks you to rebase your PR, they're saying that a lot of code has changed, and that you need to update your branch so it's easier to merge. diff --git a/tools/docs_sync.py b/tools/docs_sync.py new file mode 100644 index 0000000..bf91065 --- /dev/null +++ b/tools/docs_sync.py @@ -0,0 +1,24 @@ +import os + +def sync_docs(docs_dir='docs'): + index_path = os.path.join(docs_dir, 'index.md') + + markdown_files = [] + for root, _, files in os.walk(docs_dir): + for file in files: + if file.endswith('.md') and file != 'index.md': + rel_path = os.path.relpath(os.path.join(root, file), docs_dir) + markdown_files.append(rel_path) + + markdown_files.sort() + + os.makedirs(docs_dir, exist_ok=True) + with open(index_path, 'w', encoding='utf-8') as f: + f.write('# Documentation Index\n\n') + f.write('This index is automatically generated.\n\n') + for file in markdown_files: + title = file.replace('.md', '').replace('_', ' ').title() + f.write(f'* [{title}]({file})\n') + +if __name__ == '__main__': + sync_docs() diff --git a/tools/generate_knowledge_graph.py b/tools/generate_knowledge_graph.py new file mode 100644 index 0000000..0d3ae8f --- /dev/null +++ b/tools/generate_knowledge_graph.py @@ -0,0 +1,77 @@ +import os +import ast +import json + +def generate_knowledge_graph(root_dir='.'): + graph = { + "nodes": [], + "edges": [] + } + + file_id_counter = 1 + file_ids = {} + + for dirpath, _, filenames in os.walk(root_dir): + if any(exclude in dirpath for exclude in ['.git', '__pycache__', 'node_modules', '.venv', 'venv']): + continue + + for filename in filenames: + if not filename.endswith('.py'): + continue + + filepath = os.path.join(dirpath, filename) + + try: + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + + tree = ast.parse(content) + + file_id = f"file_{file_id_counter}" + file_ids[filepath] = file_id + file_id_counter += 1 + + graph["nodes"].append({ + "id": file_id, + "type": "file", + "path": filepath, + "label": filename + }) + + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef): + class_id = f"class_{file_id}_{node.name}" + graph["nodes"].append({ + "id": class_id, + "type": "class", + "label": node.name, + "file": filepath + }) + graph["edges"].append({ + "source": file_id, + "target": class_id, + "type": "contains" + }) + elif isinstance(node, ast.FunctionDef): + func_id = f"func_{file_id}_{node.name}" + graph["nodes"].append({ + "id": func_id, + "type": "function", + "label": node.name, + "file": filepath + }) + graph["edges"].append({ + "source": file_id, + "target": func_id, + "type": "contains" + }) + + except Exception as e: + print(f"Error parsing {filepath}: {e}") + + os.makedirs('docs', exist_ok=True) + with open('docs/knowledge_graph.json', 'w') as f: + json.dump(graph, f, indent=2) + +if __name__ == '__main__': + generate_knowledge_graph() From 4fa66379e0e878001732413d8dfa49676395df85 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 06:42:36 +0000 Subject: [PATCH 2/2] fix: resolve CI failures by correcting tool paths and actions versions - Corrected installation paths for `uv` in CI environments to target `$HOME/.local/bin/uv` instead of `$HOME/.cargo/bin/uv`. - Fixed the CodeRabbit AI PR reviewer action to use a specific stable version (`v1.17.1`) as `latest` was not resolving correctly. - Addressed Ruff lint/formatting failures in tools scripts. Co-authored-by: NITISH-R-G <225521762+NITISH-R-G@users.noreply.github.com> --- .github/workflows/ai-review.yml | 2 +- .github/workflows/ci.yml | 6 +- .github/workflows/repo-maintenance.yml | 12 ++-- tools/docs_sync.py | 20 ++++--- tools/generate_knowledge_graph.py | 77 +++++++++++++------------- 5 files changed, 59 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ai-review.yml b/.github/workflows/ai-review.yml index 3a03f1d..413391c 100644 --- a/.github/workflows/ai-review.yml +++ b/.github/workflows/ai-review.yml @@ -8,7 +8,7 @@ jobs: review: runs-on: ubuntu-latest steps: - - uses: coderabbitai/openai-pr-reviewer@latest + - uses: coderabbitai/openai-pr-reviewer@v1.17.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d99ebf9..9fd5981 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,11 +25,11 @@ jobs: - name: Install dependencies run: | - $HOME/.cargo/bin/uv venv - $HOME/.cargo/bin/uv pip install -e ".[dev]" + $HOME/.local/bin/uv venv + $HOME/.local/bin/uv pip install -e ".[dev]" - name: Run Python tests - run: $HOME/.cargo/bin/uv run pytest tests/ + run: $HOME/.local/bin/uv run pytest tests/ - name: Set up Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/repo-maintenance.yml b/.github/workflows/repo-maintenance.yml index 3699a4f..16ee9b5 100644 --- a/.github/workflows/repo-maintenance.yml +++ b/.github/workflows/repo-maintenance.yml @@ -26,11 +26,11 @@ jobs: - name: Install dependencies run: | curl -LsSf https://astral.sh/uv/install.sh | sh - $HOME/.cargo/bin/uv venv - $HOME/.cargo/bin/uv pip install --system pydeps xdg-utils cyclonedx-bom ruff + $HOME/.local/bin/uv venv + $HOME/.local/bin/uv pip install --system pydeps xdg-utils cyclonedx-bom ruff - name: Run Ruff autofix - run: ruff check --fix . || true + run: $HOME/.local/bin/uv run ruff check --fix . || true - name: Generate Knowledge Graph run: python tools/generate_knowledge_graph.py @@ -43,9 +43,9 @@ jobs: - name: Generate SBOM run: | - $HOME/.cargo/bin/uv venv - $HOME/.cargo/bin/uv pip install -e ".[dev]" - $HOME/.cargo/bin/uv run cyclonedx-py environment -o bom.json || true + $HOME/.local/bin/uv venv + $HOME/.local/bin/uv pip install -e ".[dev]" + $HOME/.local/bin/uv run cyclonedx-py environment -o bom.json || true - name: Commit changes run: | diff --git a/tools/docs_sync.py b/tools/docs_sync.py index bf91065..d8e873e 100644 --- a/tools/docs_sync.py +++ b/tools/docs_sync.py @@ -1,24 +1,26 @@ import os -def sync_docs(docs_dir='docs'): - index_path = os.path.join(docs_dir, 'index.md') + +def sync_docs(docs_dir="docs"): + index_path = os.path.join(docs_dir, "index.md") markdown_files = [] for root, _, files in os.walk(docs_dir): for file in files: - if file.endswith('.md') and file != 'index.md': + if file.endswith(".md") and file != "index.md": rel_path = os.path.relpath(os.path.join(root, file), docs_dir) markdown_files.append(rel_path) markdown_files.sort() os.makedirs(docs_dir, exist_ok=True) - with open(index_path, 'w', encoding='utf-8') as f: - f.write('# Documentation Index\n\n') - f.write('This index is automatically generated.\n\n') + with open(index_path, "w", encoding="utf-8") as f: + f.write("# Documentation Index\n\n") + f.write("This index is automatically generated.\n\n") for file in markdown_files: - title = file.replace('.md', '').replace('_', ' ').title() - f.write(f'* [{title}]({file})\n') + title = file.replace(".md", "").replace("_", " ").title() + f.write(f"* [{title}]({file})\n") + -if __name__ == '__main__': +if __name__ == "__main__": sync_docs() diff --git a/tools/generate_knowledge_graph.py b/tools/generate_knowledge_graph.py index 0d3ae8f..9b0ede5 100644 --- a/tools/generate_knowledge_graph.py +++ b/tools/generate_knowledge_graph.py @@ -2,27 +2,28 @@ import ast import json -def generate_knowledge_graph(root_dir='.'): - graph = { - "nodes": [], - "edges": [] - } + +def generate_knowledge_graph(root_dir="."): + graph = {"nodes": [], "edges": []} file_id_counter = 1 file_ids = {} for dirpath, _, filenames in os.walk(root_dir): - if any(exclude in dirpath for exclude in ['.git', '__pycache__', 'node_modules', '.venv', 'venv']): + if any( + exclude in dirpath + for exclude in [".git", "__pycache__", "node_modules", ".venv", "venv"] + ): continue for filename in filenames: - if not filename.endswith('.py'): + if not filename.endswith(".py"): continue filepath = os.path.join(dirpath, filename) try: - with open(filepath, 'r', encoding='utf-8') as f: + with open(filepath, "r", encoding="utf-8") as f: content = f.read() tree = ast.parse(content) @@ -31,47 +32,45 @@ def generate_knowledge_graph(root_dir='.'): file_ids[filepath] = file_id file_id_counter += 1 - graph["nodes"].append({ - "id": file_id, - "type": "file", - "path": filepath, - "label": filename - }) + graph["nodes"].append( + {"id": file_id, "type": "file", "path": filepath, "label": filename} + ) for node in ast.walk(tree): if isinstance(node, ast.ClassDef): class_id = f"class_{file_id}_{node.name}" - graph["nodes"].append({ - "id": class_id, - "type": "class", - "label": node.name, - "file": filepath - }) - graph["edges"].append({ - "source": file_id, - "target": class_id, - "type": "contains" - }) + graph["nodes"].append( + { + "id": class_id, + "type": "class", + "label": node.name, + "file": filepath, + } + ) + graph["edges"].append( + {"source": file_id, "target": class_id, "type": "contains"} + ) elif isinstance(node, ast.FunctionDef): func_id = f"func_{file_id}_{node.name}" - graph["nodes"].append({ - "id": func_id, - "type": "function", - "label": node.name, - "file": filepath - }) - graph["edges"].append({ - "source": file_id, - "target": func_id, - "type": "contains" - }) + graph["nodes"].append( + { + "id": func_id, + "type": "function", + "label": node.name, + "file": filepath, + } + ) + graph["edges"].append( + {"source": file_id, "target": func_id, "type": "contains"} + ) except Exception as e: print(f"Error parsing {filepath}: {e}") - os.makedirs('docs', exist_ok=True) - with open('docs/knowledge_graph.json', 'w') as f: + os.makedirs("docs", exist_ok=True) + with open("docs/knowledge_graph.json", "w") as f: json.dump(graph, f, indent=2) -if __name__ == '__main__': + +if __name__ == "__main__": generate_knowledge_graph()