From 98f22f8025e5f5f218a4a588777ba72d4add30fc Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 20:16:26 -0400 Subject: [PATCH 01/15] create github action to automate codeowner change --- .github/workflows/update-codeowners.yml | 99 +++++++++++++++++++++++++ scripts/codeowner_analyzer.py | 14 +++- 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/update-codeowners.yml diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml new file mode 100644 index 0000000000..d7ae9fba8c --- /dev/null +++ b/.github/workflows/update-codeowners.yml @@ -0,0 +1,99 @@ +name: Update CODEOWNERS + +on: + schedule: + # Run weekly on Monday at 00:00 UTC + - cron: '0 0 * * 1' + workflow_dispatch: # Allow manual triggering + +permissions: + contents: write + pull-requests: write + +jobs: + update-codeowners: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 0 # Fetch full history for accurate analysis + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Run CODEOWNERS analyzer + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + python scripts/codeowner_analyzer.py \ + --output .github/CODEOWNERS \ + --depth 3 \ + --min-commits 2 \ + --days-back 365 + + - name: Check for changes + id: check_changes + run: | + if git diff --quiet .github/CODEOWNERS; then + echo "changed=false" >> $GITHUB_OUTPUT + echo "No changes detected in CODEOWNERS" + else + echo "changed=true" >> $GITHUB_OUTPUT + echo "Changes detected in CODEOWNERS" + fi + + - name: Create Pull Request + if: steps.check_changes.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: | + chore: update CODEOWNERS based on git history + + Auto-generated CODEOWNERS update based on commit activity over the last 365 days. + + 🤖 Generated with [Claude Code](https://claude.com/claude-code) + + Co-Authored-By: Claude + branch: auto-update-codeowners + delete-branch: true + title: 'chore: Update CODEOWNERS' + body: | + ## Summary + + This PR updates the CODEOWNERS file based on git commit history analysis from the last 365 days. + + ## Changes + + - Updated `.github/CODEOWNERS` with current code ownership based on: + - Commit frequency + - File coverage + - Commit recency + + ## How to Review + + 1. Review the changes to `.github/CODEOWNERS` + 2. Verify that the assigned owners are appropriate for each module + 3. Make manual adjustments if needed before merging + + ## Notes + + - This is an automated PR generated weekly + - Minimum commits threshold: 2 + - Analysis period: 365 days + - Directory depth: 3 levels + + --- + + 🤖 This PR was automatically generated by the [update-codeowners workflow](.github/workflows/update-codeowners.yml) + labels: | + automated + maintenance + assignees: | + + reviewers: | diff --git a/scripts/codeowner_analyzer.py b/scripts/codeowner_analyzer.py index 8018244fd2..c7c6190c7e 100644 --- a/scripts/codeowner_analyzer.py +++ b/scripts/codeowner_analyzer.py @@ -31,6 +31,7 @@ def __init__( github_token: Optional[str] = None, use_api: bool = True, allowed_users: Optional[List[str]] = None, + max_depth: int = 3, ): """ Initialize the code owners analyzer. @@ -43,10 +44,12 @@ def __init__( github_token: Optional GitHub API token for higher rate limits use_api: Whether to use GitHub API for email lookups (default: True) allowed_users: Optional list of GitHub usernames to include (filters out others) + max_depth: Maximum directory depth for module detection (default: 3) """ self.repo_path = Path(repo_path).resolve() self.min_commits = min_commits self.days_back = days_back + self.max_depth = max_depth self.module_owners: DefaultDict[str, DefaultDict[str, int]] = defaultdict( lambda: defaultdict(int) ) @@ -439,8 +442,10 @@ def get_modules(self) -> List[str]: if file_ext in relevant_extensions: # Add the directory and all parent directories as modules + # Limited by max_depth path_parts = Path(dir_path).parts - for i in range(1, len(path_parts) + 1): + max_parts = min(len(path_parts), self.max_depth) + for i in range(1, max_parts + 1): module = "/".join(path_parts[:i]) if not self.should_exclude(module): modules.add(module) @@ -773,6 +778,12 @@ def main() -> int: "--allowed-users-file", help="File containing allowed GitHub usernames, one per line", ) + parser.add_argument( + "--depth", + type=int, + default=3, + help="Maximum directory depth for module detection (default: 3)", + ) args = parser.parse_args() @@ -811,6 +822,7 @@ def main() -> int: github_token=args.github_token, use_api=not args.no_api, allowed_users=allowed_users, + max_depth=args.depth, ) except ValueError as e: print(f"Error: {e}", file=sys.stderr) From b5fb3db154d8c13036ac07571f563665c063b782 Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 20:31:05 -0400 Subject: [PATCH 02/15] upd --- .github/workflows/update-codeowners.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index d7ae9fba8c..fa6fb634d5 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -34,7 +34,8 @@ jobs: --output .github/CODEOWNERS \ --depth 3 \ --min-commits 2 \ - --days-back 365 + --days-back 365 \ + --no-api - name: Check for changes id: check_changes From a87e632fefc1d919918a7d2fb5cc02a5c5367f74 Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 20:34:31 -0400 Subject: [PATCH 03/15] upd --- .github/workflows/update-codeowners.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index fa6fb634d5..86b1101ceb 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -5,6 +5,10 @@ on: # Run weekly on Monday at 00:00 UTC - cron: '0 0 * * 1' workflow_dispatch: # Allow manual triggering + # NOTE(Zihao): debugging only, remove later + pull_request: + branches: + - main permissions: contents: write From 4e22b6b3dbd80c38d6fbb03ea73339717c4704f7 Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 21:53:22 -0400 Subject: [PATCH 04/15] upd --- .github/workflows/update-codeowners.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 86b1101ceb..9c500ccc2e 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -44,7 +44,11 @@ jobs: - name: Check for changes id: check_changes run: | - if git diff --quiet .github/CODEOWNERS; then + # Check if CODEOWNERS is empty or has changed + if [ ! -s .github/CODEOWNERS ]; then + echo "changed=true" >> $GITHUB_OUTPUT + echo "CODEOWNERS is empty or missing" + elif git diff --quiet .github/CODEOWNERS; then echo "changed=false" >> $GITHUB_OUTPUT echo "No changes detected in CODEOWNERS" else From f8a1a8cfe71e6a4773a4b0793387e362499b74ec Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 21:57:11 -0400 Subject: [PATCH 05/15] upd --- .github/workflows/update-codeowners.yml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 9c500ccc2e..867781532b 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -44,16 +44,20 @@ jobs: - name: Check for changes id: check_changes run: | - # Check if CODEOWNERS is empty or has changed - if [ ! -s .github/CODEOWNERS ]; then - echo "changed=true" >> $GITHUB_OUTPUT - echo "CODEOWNERS is empty or missing" - elif git diff --quiet .github/CODEOWNERS; then - echo "changed=false" >> $GITHUB_OUTPUT - echo "No changes detected in CODEOWNERS" + # Check if CODEOWNERS file is new (unstaged) or has changes + if git ls-files --error-unmatch .github/CODEOWNERS >/dev/null 2>&1; then + # File is tracked, check for changes + if git diff --quiet .github/CODEOWNERS; then + echo "changed=false" >> $GITHUB_OUTPUT + echo "No changes detected in CODEOWNERS" + else + echo "changed=true" >> $GITHUB_OUTPUT + echo "Changes detected in CODEOWNERS" + fi else + # File is untracked (newly created) echo "changed=true" >> $GITHUB_OUTPUT - echo "Changes detected in CODEOWNERS" + echo "CODEOWNERS file is new" fi - name: Create Pull Request From d4df395c8b910af9de383e8fa6f2423671045e11 Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:03:03 -0400 Subject: [PATCH 06/15] upd --- .github/workflows/update-codeowners.yml | 5 +++-- scripts/codeowner_analyzer.py | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 867781532b..329c907299 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -37,8 +37,9 @@ jobs: python scripts/codeowner_analyzer.py \ --output .github/CODEOWNERS \ --depth 3 \ - --min-commits 2 \ - --days-back 365 \ + --min-commits 1 \ + --days-back 180 \ + --top-n 5 \ --no-api - name: Check for changes diff --git a/scripts/codeowner_analyzer.py b/scripts/codeowner_analyzer.py index c7c6190c7e..b18ec0a807 100644 --- a/scripts/codeowner_analyzer.py +++ b/scripts/codeowner_analyzer.py @@ -32,6 +32,7 @@ def __init__( use_api: bool = True, allowed_users: Optional[List[str]] = None, max_depth: int = 3, + top_n_owners: int = 3, ): """ Initialize the code owners analyzer. @@ -45,11 +46,13 @@ def __init__( use_api: Whether to use GitHub API for email lookups (default: True) allowed_users: Optional list of GitHub usernames to include (filters out others) max_depth: Maximum directory depth for module detection (default: 3) + top_n_owners: Number of top owners to include in CODEOWNERS file (default: 3) """ self.repo_path = Path(repo_path).resolve() self.min_commits = min_commits self.days_back = days_back self.max_depth = max_depth + self.top_n_owners = top_n_owners self.module_owners: DefaultDict[str, DefaultDict[str, int]] = defaultdict( lambda: defaultdict(int) ) @@ -659,10 +662,10 @@ def generate_codeowners_file( for module, data in results.items(): if data["owners"]: - # Take top 3 owners or those with ownership score > 0.1 + # Take top N owners or those with ownership score > 0.1 top_owners = [ owner - for owner in data["owners"][:3] + for owner in data["owners"][: self.top_n_owners] if owner["ownership_score"] > 0.1 ] @@ -784,6 +787,12 @@ def main() -> int: default=3, help="Maximum directory depth for module detection (default: 3)", ) + parser.add_argument( + "--top-n", + type=int, + default=3, + help="Number of top owners to include in CODEOWNERS file (default: 3)", + ) args = parser.parse_args() @@ -823,6 +832,7 @@ def main() -> int: use_api=not args.no_api, allowed_users=allowed_users, max_depth=args.depth, + top_n_owners=args.top_n, ) except ValueError as e: print(f"Error: {e}", file=sys.stderr) From 757cb326ebdac5d50c2ff3801bd0c79ec84c36b8 Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:05:29 -0400 Subject: [PATCH 07/15] upd --- .github/workflows/update-codeowners.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 329c907299..66520d49a1 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -75,6 +75,7 @@ jobs: Co-Authored-By: Claude branch: auto-update-codeowners + base: main delete-branch: true title: 'chore: Update CODEOWNERS' body: | From 3934511289a8155772762407722ca1375b5dcf4a Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:08:42 -0400 Subject: [PATCH 08/15] upd --- .github/workflows/update-codeowners.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 66520d49a1..b4a0db6827 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4.2.2 with: fetch-depth: 0 # Fetch full history for accurate analysis - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} - name: Set up Python uses: actions/setup-python@v5 @@ -32,7 +32,7 @@ jobs: - name: Run CODEOWNERS analyzer env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} run: | python scripts/codeowner_analyzer.py \ --output .github/CODEOWNERS \ @@ -65,7 +65,7 @@ jobs: if: steps.check_changes.outputs.changed == 'true' uses: peter-evans/create-pull-request@v7 with: - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} commit-message: | chore: update CODEOWNERS based on git history From 560b43497b58dd305a3c59fefed4504ea80b4f7c Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:11:18 -0400 Subject: [PATCH 09/15] Revert "upd" This reverts commit 3934511289a8155772762407722ca1375b5dcf4a. --- .github/workflows/update-codeowners.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index b4a0db6827..66520d49a1 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v4.2.2 with: fetch-depth: 0 # Fetch full history for accurate analysis - token: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} - name: Set up Python uses: actions/setup-python@v5 @@ -32,7 +32,7 @@ jobs: - name: Run CODEOWNERS analyzer env: - GITHUB_TOKEN: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | python scripts/codeowner_analyzer.py \ --output .github/CODEOWNERS \ @@ -65,7 +65,7 @@ jobs: if: steps.check_changes.outputs.changed == 'true' uses: peter-evans/create-pull-request@v7 with: - token: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} commit-message: | chore: update CODEOWNERS based on git history From 130b8b317d5d99ccf4c4964d0ef316d95d094ac2 Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:18:40 -0400 Subject: [PATCH 10/15] upd --- .github/workflows/update-codeowners.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 66520d49a1..2a7dfcba9a 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -65,7 +65,7 @@ jobs: if: steps.check_changes.outputs.changed == 'true' uses: peter-evans/create-pull-request@v7 with: - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} commit-message: | chore: update CODEOWNERS based on git history From 3b5e0aa7f951dcc49b603a9785aa5069a6809763 Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:25:53 -0400 Subject: [PATCH 11/15] upd --- .github/workflows/update-codeowners.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 2a7dfcba9a..cfe836ac35 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -6,7 +6,7 @@ on: - cron: '0 0 * * 1' workflow_dispatch: # Allow manual triggering # NOTE(Zihao): debugging only, remove later - pull_request: + pull_request_target: branches: - main @@ -65,7 +65,7 @@ jobs: if: steps.check_changes.outputs.changed == 'true' uses: peter-evans/create-pull-request@v7 with: - token: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} commit-message: | chore: update CODEOWNERS based on git history From c4027303a1a393cb729ae43757c5aa066f3d72cf Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:29:16 -0400 Subject: [PATCH 12/15] test: switch to pull_request with FLASHINFER_GITHUB_TOKEN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing if the token has permission to create PRs from pull_request trigger. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/update-codeowners.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index cfe836ac35..2a7dfcba9a 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -6,7 +6,7 @@ on: - cron: '0 0 * * 1' workflow_dispatch: # Allow manual triggering # NOTE(Zihao): debugging only, remove later - pull_request_target: + pull_request: branches: - main @@ -65,7 +65,7 @@ jobs: if: steps.check_changes.outputs.changed == 'true' uses: peter-evans/create-pull-request@v7 with: - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} commit-message: | chore: update CODEOWNERS based on git history From f0385496efd46cdb49a0d7668f7cd9c14df09c39 Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:40:04 -0400 Subject: [PATCH 13/15] chore: remove pull_request trigger from update-codeowners workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use workflow_dispatch for testing instead to ensure secrets are accessible. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/update-codeowners.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 2a7dfcba9a..a48c2f61f2 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -5,10 +5,6 @@ on: # Run weekly on Monday at 00:00 UTC - cron: '0 0 * * 1' workflow_dispatch: # Allow manual triggering - # NOTE(Zihao): debugging only, remove later - pull_request: - branches: - - main permissions: contents: write @@ -65,7 +61,7 @@ jobs: if: steps.check_changes.outputs.changed == 'true' uses: peter-evans/create-pull-request@v7 with: - token: ${{ secrets.FLASHINFER_GITHUB_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} commit-message: | chore: update CODEOWNERS based on git history From 9cc7e985e8ab214559ef7fd53818473e246e511f Mon Sep 17 00:00:00 2001 From: Zihao Ye Date: Sun, 5 Oct 2025 22:53:02 -0400 Subject: [PATCH 14/15] upd --- .github/workflows/update-codeowners.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index a48c2f61f2..0b3f2f04a0 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -5,6 +5,9 @@ on: # Run weekly on Monday at 00:00 UTC - cron: '0 0 * * 1' workflow_dispatch: # Allow manual triggering + pull_request: + branches: + - main permissions: contents: write From 75476931c7dd0c59222cdfdb6ab95cd08451abd7 Mon Sep 17 00:00:00 2001 From: yzh119 Date: Mon, 6 Oct 2025 10:09:42 -0700 Subject: [PATCH 15/15] disable triggering from pull request --- .github/workflows/update-codeowners.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/update-codeowners.yml b/.github/workflows/update-codeowners.yml index 0b3f2f04a0..a48c2f61f2 100644 --- a/.github/workflows/update-codeowners.yml +++ b/.github/workflows/update-codeowners.yml @@ -5,9 +5,6 @@ on: # Run weekly on Monday at 00:00 UTC - cron: '0 0 * * 1' workflow_dispatch: # Allow manual triggering - pull_request: - branches: - - main permissions: contents: write