|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Auto Assign Action is a GitHub Action that automatically adds reviewers and/or assignees to pull requests when they are opened. The action reads a YAML configuration file (default: `.github/auto_assign.yml`) and assigns users based on single or grouped reviewer lists, with support for filtering by labels, draft status, and skip keywords. |
| 8 | + |
| 9 | +## Development Commands |
| 10 | + |
| 11 | +### Build and Test |
| 12 | +```bash |
| 13 | +npm run build # Compile TypeScript to lib/ directory |
| 14 | +npm test # Run all Jest tests |
| 15 | +npm run format # Format all TypeScript files with Prettier |
| 16 | +npm run format-check # Check formatting without modifying files |
| 17 | +npm run package # Bundle with ncc into dist/index.js for distribution |
| 18 | +``` |
| 19 | + |
| 20 | +### Running Individual Tests |
| 21 | +```bash |
| 22 | +npm test -- __tests__/utils.test.ts # Run specific test file |
| 23 | +npm test -- -t "test name pattern" # Run tests matching pattern |
| 24 | +``` |
| 25 | + |
| 26 | +## Architecture |
| 27 | + |
| 28 | +### Entry Point Flow |
| 29 | +1. **main.ts** - Entry point that calls `run()` |
| 30 | +2. **run.ts** - Orchestrates the action: |
| 31 | + - Fetches inputs (`repo-token`, `configuration-path`) |
| 32 | + - Creates GitHub Octokit client |
| 33 | + - Loads config from repository using `utils.fetchConfigurationFile()` |
| 34 | + - Delegates to `handler.handlePullRequest()` |
| 35 | + |
| 36 | +### Core Components |
| 37 | + |
| 38 | +**handler.ts** - Main business logic |
| 39 | +- `handlePullRequest()`: Validates PR against filters (skip keywords, draft status, labels), then adds reviewers and assignees |
| 40 | +- `Config` interface: Defines all configuration options from YAML file |
| 41 | +- Filters execute in order: skip keywords → draft check → label filters → assignment |
| 42 | + |
| 43 | +**utils.ts** - Selection logic |
| 44 | +- `chooseReviewers()` / `chooseAssignees()`: Select users from single list or groups |
| 45 | +- `chooseUsers()`: Filters out PR creator, returns all users if `numberOfReviewers: 0`, otherwise randomly samples |
| 46 | +- `chooseUsersFromGroups()`: Iterates groups and selects users from each |
| 47 | +- `fetchConfigurationFile()`: Retrieves and parses YAML config from repository via GitHub API |
| 48 | + |
| 49 | +**pull_request.ts** - GitHub API wrapper |
| 50 | +- `PullRequest` class encapsulates context and client |
| 51 | +- `addReviewers()`: Calls `pulls.requestReviewers` API |
| 52 | +- `addAssignees()`: Calls `issues.addAssignees` API (PRs are issues) |
| 53 | +- `hasAnyLabel()`: Checks if PR has any of the specified labels |
| 54 | + |
| 55 | +### Configuration System |
| 56 | + |
| 57 | +The action expects a YAML configuration file (default `.github/auto_assign.yml`) with these key options: |
| 58 | +- `addReviewers` / `addAssignees`: Enable reviewer/assignee assignment |
| 59 | +- `reviewers` / `assignees`: Single list mode |
| 60 | +- `useReviewGroups` / `useAssigneeGroups`: Enable grouped mode |
| 61 | +- `reviewGroups` / `assigneeGroups`: Multiple lists keyed by group name |
| 62 | +- `numberOfReviewers` / `numberOfAssignees`: How many to assign (0 = all) |
| 63 | +- `skipKeywords`: Skip assignment if PR title contains these |
| 64 | +- `filterLabels.include` / `filterLabels.exclude`: Label-based filtering |
| 65 | +- `runOnDraft`: Whether to run on draft PRs (default: false) |
| 66 | +- Special: `addAssignees: "author"` assigns PR creator as assignee |
| 67 | + |
| 68 | +### Key Behaviors |
| 69 | + |
| 70 | +- **PR Creator Exclusion**: The PR author is always filtered out from reviewers/assignees (unless `addAssignees: "author"`) |
| 71 | +- **Random Sampling**: When `numberOfReviewers` > 0, uses `lodash.sampleSize()` for random selection |
| 72 | +- **Group Mode**: When using groups, the specified number is selected from EACH group, not total |
| 73 | +- **Error Handling**: Reviewer/assignee addition failures are logged as warnings, not failures |
| 74 | +- **Configuration Validation**: Throws errors if group flags are enabled but group lists are missing |
| 75 | + |
| 76 | +### Distribution |
| 77 | + |
| 78 | +The action uses `@vercel/ncc` to bundle everything into `dist/index.js`. After making changes: |
| 79 | +1. Run `npm run build` to compile TypeScript |
| 80 | +2. Run `npm run package` to create the bundled distribution |
| 81 | +3. Commit both `lib/` and `dist/` directories |
| 82 | + |
| 83 | +The action runs on Node 20 (specified in `action.yml`). |
| 84 | + |
| 85 | +### Testing |
| 86 | + |
| 87 | +Tests use Jest with ts-jest transformer. Test files mirror source structure: |
| 88 | +- `__tests__/utils.test.ts` - Tests selection logic and utility functions |
| 89 | +- `__tests__/handler.test.ts` - Tests main handler logic and filtering |
| 90 | +- `__tests__/run.test.ts` - Tests action entry point |
| 91 | + |
| 92 | +Mock `@actions/github` for testing without real API calls. |
0 commit comments