From 10dfb4ceaa6c30b95cf248362cd0304939617bdf Mon Sep 17 00:00:00 2001 From: Shrinath Rao Date: Wed, 10 Jun 2026 12:31:21 +0530 Subject: [PATCH] ci: auto-assign metadata with team allowlist, start date, and stranger triage (#12543) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Extends the `auto-assign-metadata` workflow with three improvements: - **Creator classification** — a new first step buckets every issue/PR creator into one of three categories: - `team` — 23-person engineering allowlist → full workflow runs (assign self, milestone, add to project, set start date) - `internal` — other org members not on the allowlist → silently skipped - `stranger` — not an org member at all → assigned to designated triagers - **Start date** — on new issues, captures the project item ID and sets the `Start Date` field in GitHub Project #19 to today's UTC date via `updateProjectV2ItemFieldValue` - **Stranger triage** (OSS only) — issues from external contributors are assigned to `Shrinath-O2` + `Manazsharma` + `neha00290`; PRs are assigned to `oasisk` + `hengfeiyang` ### Who gets what | Category | Members | Issues | PRs | |---|---|---|---| | **Engineering team** | `bjp232004` `hengfeiyang` `prabhatsharma` `uddhavdave` `oasisk` `haohuaijin` `Subhra264` `Loaki07` `007harshmahajan` `chaitanya-sistla` `ktx-kirtan` `omkarK06` `ktx-vaidehi` `ktx-abhay` `neha00290` `ktx-akshay` `ktx-sadhna` `nikhilsaikethe` `YashodhanJoshi1` `ktx-riya` `mmosarafO2` `Shrinath-O2` `ktx-mihir` | Assign self · milestone · project · start date | Assign self · milestone · project | | **Internal — skipped** | `sowjanyapuvvula` `ravenwh` `abvarun226` `ysantosh` `luckykurhe` `achatterjee4` `akshaye-blip` `Udhankaran` `jakeopenobserve` `Manazsharma` `manoj0881-git` `gorakhnathy7` `simranquirky` `roniandgit` `sandydgenius` `javasks` `Yadumathur` | Skip | Skip | | **Stranger** | Anyone not in org | Assign `Shrinath-O2` + `Manazsharma` + `neha00290` | Assign `oasisk` + `hengfeiyang` | ## Test plan - [ ] Open a new issue as an engineering team member → verify self-assigned, milestone set, added to project, Start Date populated - [ ] Open a new issue as a stranger → verify assigned to Shrinath-O2 + Manazsharma + neha00290 only - [ ] Open a PR as an engineering team member → verify self-assigned and milestone set - [ ] Open a PR as a stranger → verify assigned to oasisk + hengfeiyang only - [ ] Open an issue as an internal (skipped) member → verify no changes made 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 --- .github/workflows/auto-assign-metadata.yml | 99 ++++++++++++++++++++-- 1 file changed, 90 insertions(+), 9 deletions(-) diff --git a/.github/workflows/auto-assign-metadata.yml b/.github/workflows/auto-assign-metadata.yml index d7f74d8055..1db6bc215a 100644 --- a/.github/workflows/auto-assign-metadata.yml +++ b/.github/workflows/auto-assign-metadata.yml @@ -17,9 +17,31 @@ jobs: auto-assign: runs-on: ubuntu-latest steps: + # ── Classify creator: team | internal | stranger ── + - name: Classify creator + id: classify + env: + GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} + ORG: ${{ github.repository_owner }} + CREATOR: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.user.login || github.event.issue.user.login }} + run: | + ALLOWLIST=" bjp232004 hengfeiyang prabhatsharma uddhavdave oasisk haohuaijin Subhra264 Loaki07 007harshmahajan chaitanya-sistla ktx-kirtan omkarK06 ktx-vaidehi ktx-abhay neha00290 ktx-akshay ktx-sadhna nikhilsaikethe YashodhanJoshi1 ktx-riya mmosarafO2 Shrinath-O2 ktx-mihir " + CREATOR_LOWER=$(echo "$CREATOR" | tr '[:upper:]' '[:lower:]') + ALLOWLIST_LOWER=$(echo "$ALLOWLIST" | tr '[:upper:]' '[:lower:]') + if echo "$ALLOWLIST_LOWER" | grep -q " $CREATOR_LOWER "; then + echo "category=team" >> "$GITHUB_OUTPUT" + echo "Creator $CREATOR is on the engineering team" + elif gh api "orgs/$ORG/members/$CREATOR" --silent 2>/dev/null; then + echo "category=internal" >> "$GITHUB_OUTPUT" + echo "Creator $CREATOR is an internal member (not engineering team) — skipping" + else + echo "category=stranger" >> "$GITHUB_OUTPUT" + echo "Creator $CREATOR is an external contributor" + fi + # ── PR: assign creator ── - name: Assign PR creator - if: github.event_name == 'pull_request_target' + if: github.event_name == 'pull_request_target' && steps.classify.outputs.category == 'team' env: GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} GH_REPO: ${{ github.repository }} @@ -32,7 +54,7 @@ jobs: # ── PR: add lowest open milestone (skip drafts) ── - name: Add milestone to PR - if: github.event_name == 'pull_request_target' && github.event.pull_request.draft == false && github.event.pull_request.base.ref == 'main' + if: github.event_name == 'pull_request_target' && steps.classify.outputs.category == 'team' && github.event.pull_request.draft == false && github.event.pull_request.base.ref == 'main' env: GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} GH_REPO: ${{ github.repository }} @@ -68,7 +90,7 @@ jobs: # ── PR: add to project ── - name: Add PR to project - if: github.event_name == 'pull_request_target' + if: github.event_name == 'pull_request_target' && steps.classify.outputs.category == 'team' env: GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} NODE_ID: ${{ github.event.pull_request.node_id }} @@ -90,7 +112,7 @@ jobs: # ── Issue: assign creator if unassigned ── - name: Assign issue creator - if: github.event_name == 'issues' + if: github.event_name == 'issues' && steps.classify.outputs.category == 'team' env: GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} GH_REPO: ${{ github.repository }} @@ -108,7 +130,7 @@ jobs: # ── Issue: add lowest open milestone ── - name: Add milestone to issue - if: github.event_name == 'issues' + if: github.event_name == 'issues' && steps.classify.outputs.category == 'team' env: GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} GH_REPO: ${{ github.repository }} @@ -144,7 +166,8 @@ jobs: # ── Issue: add to project ── - name: Add issue to project - if: github.event_name == 'issues' + id: add_issue_to_project + if: github.event_name == 'issues' && steps.classify.outputs.category == 'team' env: GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} NODE_ID: ${{ github.event.issue.node_id }} @@ -157,9 +180,67 @@ jobs: [ -n "$PROJECT_ID" ] || { echo "::warning::Project not found — check PROJECT_NUMBER and token scope"; exit 0; } - gh api graphql \ + ITEM_ID=$(gh api graphql \ -f query='mutation($project:ID!,$content:ID!){addProjectV2ItemById(input:{projectId:$project,contentId:$content}){item{id}}}' \ -f project="$PROJECT_ID" \ -f content="$NODE_ID" \ - && echo "Added issue to project" \ - || echo "::warning::Could not add issue to project" + --jq '.data.addProjectV2ItemById.item.id') + + if [ -n "$ITEM_ID" ]; then + echo "Added issue to project (item: $ITEM_ID)" + echo "item_id=$ITEM_ID" >> "$GITHUB_OUTPUT" + echo "project_id=$PROJECT_ID" >> "$GITHUB_OUTPUT" + else + echo "::warning::Could not add issue to project" + fi + + # ── Issue: set start date ── + - name: Set start date on issue + if: github.event_name == 'issues' && steps.classify.outputs.category == 'team' && steps.add_issue_to_project.outputs.item_id != '' + env: + GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} + ORG: ${{ github.repository_owner }} + ITEM_ID: ${{ steps.add_issue_to_project.outputs.item_id }} + PROJECT_ID: ${{ steps.add_issue_to_project.outputs.project_id }} + run: | + TODAY=$(date -u +%Y-%m-%d) + + FIELD_ID=$(gh api graphql \ + -f query='query($project:ID!){node(id:$project){... on ProjectV2{fields(first:30){nodes{... on ProjectV2Field{id name}}}}}}' \ + -f project="$PROJECT_ID" \ + --jq '[.data.node.fields.nodes[] | select(.name | ascii_downcase == "start date")] | .[0].id // empty') + + [ -n "$FIELD_ID" ] || { echo "::warning::Start date field not found in project"; exit 0; } + + MUTATION_OUT=$(gh api graphql \ + -f query='mutation($project:ID!,$item:ID!,$field:ID!,$date:Date!){updateProjectV2ItemFieldValue(input:{projectId:$project,itemId:$item,fieldId:$field,value:{date:$date}}){projectV2Item{id}}}' \ + -f project="$PROJECT_ID" \ + -f item="$ITEM_ID" \ + -f field="$FIELD_ID" \ + -f date="$TODAY" 2>&1) \ + && echo "Set start date to $TODAY" \ + || echo "::warning::Could not set start date: $MUTATION_OUT" + + # ── Stranger: assign issue to Shrinath + Manas ── + - name: Assign stranger issue + if: github.event_name == 'issues' && steps.classify.outputs.category == 'stranger' + env: + GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.issue.number }} + run: | + gh issue edit "$NUMBER" --add-assignee "Shrinath-O2" --add-assignee "Manazsharma" --add-assignee "neha00290" \ + && echo "Assigned Shrinath-O2, Manazsharma and neha00290 to stranger issue #$NUMBER" \ + || echo "::warning::Could not assign to stranger issue #$NUMBER" + + # ── Stranger: assign PR to oasisk + hengfeiyang ── + - name: Assign stranger PR + if: github.event_name == 'pull_request_target' && steps.classify.outputs.category == 'stranger' + env: + GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.pull_request.number }} + run: | + gh pr edit "$NUMBER" --add-assignee "oasisk" --add-assignee "hengfeiyang" \ + && echo "Assigned oasisk and hengfeiyang to stranger PR #$NUMBER" \ + || echo "::warning::Could not assign to stranger PR #$NUMBER"