@hardlydifficult/pr-analyzer 1.0.73 → 1.0.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +107 -82
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hardlydifficult/pr-analyzer
2
2
 
3
- GitHub PR analyzer that classifies pull requests and determines available actions like merge, mark ready, and auto-merge.
3
+ A TypeScript package for analyzing GitHub pull requests and classifying them into actionable buckets.
4
4
 
5
5
  ## Installation
6
6
 
@@ -11,60 +11,93 @@ npm install @hardlydifficult/pr-analyzer
11
11
  ## Quick Start
12
12
 
13
13
  ```typescript
14
- import { scanSinglePR } from "@hardlydifficult/pr-analyzer";
15
14
  import { GitHubClient } from "@hardlydifficult/github";
15
+ import { scanSinglePR } from "@hardlydifficult/pr-analyzer";
16
16
 
17
- const client = new GitHubClient(process.env.GITHUB_TOKEN!);
17
+ // Create a GitHub client
18
+ const client = new GitHubClient({ token: "ghp_..." });
19
+
20
+ // Scan a PR
18
21
  const pr = await scanSinglePR(
19
22
  client,
20
- "@cursor", // Bot mention command
21
- "HardlyDifficult", // Owner
22
- "typescript", // Repo
23
- 42, // PR number
23
+ "@cursor",
24
+ "owner",
25
+ "repo",
26
+ 123
24
27
  );
25
28
 
26
- console.log(pr.status); // e.g. "ready_to_merge"
27
- console.log(pr.ciSummary); // e.g. "CI passed: 1 checks"
29
+ // Check status and available actions
30
+ console.log(pr.status); // "ready_to_merge"
31
+ console.log(pr.ciSummary); // "CI passed: 3 checks"
32
+
33
+ import { getAvailableActions } from "@hardlydifficult/pr-analyzer";
34
+ const actions = getAvailableActions(pr);
35
+ // actions = [{ type: "merge", label: "Merge", description: "Squash and merge this PR" }]
28
36
  ```
29
37
 
30
38
  ## Core Features
31
39
 
32
40
  ### Scanning and Analyzing PRs
33
41
 
34
- Scan a single PR in real-time using GitHub client, repository owner, repo name, and PR number.
42
+ #### `analyzePR`
43
+
44
+ Analyzes a single PR and returns its full status.
35
45
 
36
46
  ```typescript
37
- import { scanSinglePR, analyzeAll } from "@hardlydifficult/pr-analyzer";
38
- import type { DiscoveredPR, AnalyzerHooks, Logger } from "@hardlydifficult/pr-analyzer";
47
+ import { analyzePR, analyzeAll } from "@hardlydifficult/pr-analyzer";
48
+
49
+ const pr = await client.repo("owner", "repo").pr(123).get();
50
+ const scanned = await analyzePR(client, "owner", "repo", pr, "@bot");
51
+
52
+ scanned.status; // "ready_to_merge"
53
+ scanned.hasConflicts; // false
54
+ scanned.daysSinceUpdate; // 2
55
+ ```
56
+
57
+ #### `analyzeAll`
39
58
 
40
- // Scan a single PR
41
- const pr = await scanSinglePR(client, "@bot", "owner", "repo", 42);
59
+ Analyzes multiple PRs in parallel, logging failures.
60
+
61
+ ```typescript
62
+ import type { DiscoveredPR } from "@hardlydifficult/pr-analyzer";
42
63
 
43
- // Analyze a batch of discovered PRs
44
- const discovered: DiscoveredPR[] = [
45
- { pr, repoOwner: "owner", repoName: "repo" },
64
+ const prs: readonly DiscoveredPR[] = [
65
+ { pr: pr1, repoOwner: "owner", repoName: "repo" },
66
+ { pr: pr2, repoOwner: "owner", repoName: "repo" },
46
67
  ];
47
- const results = await analyzeAll(discovered, client, "@bot", console as Logger);
68
+
69
+ const results = await analyzeAll(prs, client, "@bot");
70
+ // results = [scannedPR1, scannedPR2]
71
+ ```
72
+
73
+ #### `scanSinglePR`
74
+
75
+ Scans a single PR directly by repo and number (real-time event handling).
76
+
77
+ ```typescript
78
+ import { scanSinglePR } from "@hardlydifficult/pr-analyzer";
79
+
80
+ const pr = await scanSinglePR(client, "@cursor", "owner", "repo", 456);
48
81
  ```
49
82
 
50
83
  ### PR Status Determination
51
84
 
52
- Core statuses are derived from GitHub data:
85
+ PRs are classified into core statuses based on priority:
53
86
 
54
- - `"draft"` — PR is in draft state
55
- - `"ci_running"` — CI checks are in progress
56
- - `"ci_failed"` — At least one CI check failed
57
- - `"needs_review"` — No reviewer approval yet
58
- - `"changes_requested"` — A reviewer requested changes
59
- - `"approved"` — At least one reviewer approved
60
- - `"has_conflicts"` — Merge conflicts detected
61
- - `"ready_to_merge"` — CI passed, no conflicts, approved
62
- - `"waiting_on_bot"` — Bot was mentioned and has not replied
87
+ 1. `draft` — PR is a draft
88
+ 2. `ci_running` — CI checks are in progress
89
+ 3. `ci_failed` — At least one CI check failed
90
+ 4. `has_conflicts` — PR has merge conflicts
91
+ 5. `waiting_on_bot` — A bot was mentioned and hasn’t responded
92
+ 6. `changes_requested` — A reviewer requested changes
93
+ 7. `ready_to_merge` — CI passed and no conflicts
94
+ 8. `approved` — PR approved (but not all CI passed)
95
+ 9. `needs_review` — No reviews or approvals yet
63
96
 
64
- You can extend status determination via `AnalyzerHooks.resolveStatus`.
97
+ Extensions via `AnalyzerHooks.resolveStatus` allow custom statuses.
65
98
 
66
99
  ```typescript
67
- const hooks: AnalyzerHooks = {
100
+ const hooks = {
68
101
  resolveStatus: (coreStatus, details) => {
69
102
  if (coreStatus === "ci_failed" && details.checks.some(c => c.name === "CI")) {
70
103
  return "ai_processing";
@@ -79,87 +112,79 @@ console.log(pr.status); // e.g. "ai_processing"
79
112
 
80
113
  ### Classification
81
114
 
82
- Classify PRs into action buckets.
115
+ Classifies PRs into action buckets: `readyForHuman`, `needsBotBump`, `inProgress`, `blocked`.
83
116
 
84
117
  ```typescript
85
118
  import { classifyPRs } from "@hardlydifficult/pr-analyzer";
86
119
 
87
- const result = classifyPRs(results);
88
- console.log(result.readyForHuman); // PRs needing human review/merge
89
- console.log(result.inProgress); // PRs with CI running
90
- console.log(result.blocked); // PRs blocked (draft, failed CI, conflicts)
91
- console.log(result.needsBotBump); // PRs waiting on bot response
120
+ const result = classifyPRs([scannedPR1, scannedPR2]);
121
+ result.readyForHuman; // PRs needing human review/merge
122
+ result.needsBotBump; // PRs waiting on bot response
123
+ result.inProgress; // PRs with CI running
124
+ result.blocked; // PRs stalled (draft, failed CI, conflicts)
92
125
  ```
93
126
 
94
- Extend classification buckets with custom statuses via `ClassificationConfig`.
127
+ #### ClassificationConfig
128
+
129
+ Extend buckets with custom statuses:
95
130
 
96
131
  ```typescript
97
- const config: ClassificationConfig = {
132
+ const config = {
133
+ readyForHuman: ["custom_status"],
98
134
  inProgress: ["ai_processing"],
99
- blocked: ["security_review"],
135
+ blocked: ["custom_blocked"],
136
+ needsBotBump: ["custom_waiting"],
100
137
  };
101
- const result = classifyPRs(results, config);
138
+
139
+ const result = classifyPRs(prs, config);
102
140
  ```
103
141
 
104
142
  ### Available Actions
105
143
 
106
- Determine available actions for a PR.
144
+ Determines which actions are available for a PR based on its status.
145
+
146
+ #### Core Actions
147
+
148
+ - `merge` — Available for `ready_to_merge`, `approved`
149
+ - `mark_ready` — Available for `draft` when CI passed and no conflicts
150
+ - `enable_auto_merge` — Available for `ci_running`, `needs_review` when PR is not draft, not merged, no conflicts
107
151
 
108
152
  ```typescript
109
153
  import { getAvailableActions, PR_ACTIONS } from "@hardlydifficult/pr-analyzer";
110
154
 
111
155
  const actions = getAvailableActions(pr);
112
- console.log(actions.map(a => a.label)); // e.g. ["Merge", "Enable Auto-Merge"]
156
+ // [{ type: "merge", label: "Merge", description: "Squash and merge this PR" }]
113
157
  ```
114
158
 
115
- Core actions:
159
+ #### Custom Actions
116
160
 
117
- | Type | Label | Description |
118
- |------------------|---------------|------------------------------------------|
119
- | `"merge"` | `"Merge"` | Squash and merge this PR |
120
- | `"mark_ready"` | `"Mark Ready"`| Mark this draft PR as ready for review |
121
- | `"enable_auto_merge"` | `"Enable Auto-Merge"` | Enable GitHub auto-merge when checks pass |
122
-
123
- Add custom actions with `ActionDefinition`.
161
+ Consumers can define extra actions with custom conditions.
124
162
 
125
163
  ```typescript
126
- const extraActions: ActionDefinition[] = [
127
- {
128
- type: "fix_ci",
129
- label: "Fix CI",
130
- description: "Post @cursor fix CI comment",
131
- when: (pr, ctx) => pr.status === "ci_failed" && ctx["isWorkPR"] === true,
132
- },
133
- ];
164
+ import { ActionDefinition } from "@hardlydifficult/pr-analyzer";
165
+
166
+ const fixCiAction: ActionDefinition = {
167
+ type: "fix_ci",
168
+ label: "Fix CI",
169
+ description: "Post @cursor fix CI comment",
170
+ when: (pr, ctx) => pr.status === "ci_failed" && ctx["isWorkPR"] === true,
171
+ };
134
172
 
135
- const actions = getAvailableActions(pr, extraActions, { isWorkPR: true });
173
+ const actions = getAvailableActions(pr, [fixCiAction], { isWorkPR: true });
136
174
  ```
137
175
 
138
176
  ## Types and Interfaces
139
177
 
140
- ```typescript
141
- import type {
142
- ScannedPR,
143
- CIStatus,
144
- ScanResult,
145
- AnalyzerHooks,
146
- ClassificationConfig,
147
- ActionDefinition,
148
- CorePRStatus,
149
- Logger,
150
- } from "@hardlydifficult/pr-analyzer";
151
- ```
152
-
153
- | Interface/Type | Purpose |
154
- |---------------------|---------|
155
- | `ScannedPR` | Full PR data after analysis |
156
- | `CIStatus` | CI check summary (running, failed, passed) |
157
- | `ScanResult` | PRs grouped into buckets |
158
- | `AnalyzerHooks` | Extend status determination |
159
- | `ClassificationConfig` | Extend classification buckets |
160
- | `ActionDefinition` | Define custom PR actions |
161
- | `CorePRStatus` | Built-in status types |
162
- | `Logger` | Interface for logging info/errors |
178
+ | Type | Description |
179
+ |------|-------------|
180
+ | `ScannedPR` | A fully analyzed PR with status, CI summary, and metadata |
181
+ | `ScanResult` | Classified PR buckets: `all`, `readyForHuman`, `needsBotBump`, `inProgress`, `blocked` |
182
+ | `AnalyzerHooks` | Custom logic hook: `resolveStatus(coreStatus, details)` |
183
+ | `ClassificationConfig` | Extend status buckets with custom statuses |
184
+ | `ActionDefinition` | Define custom actions with conditional logic |
185
+ | `CorePRStatus` | Core PR status enum (`draft`, `ci_running`, etc.) |
186
+ | `CIStatus` | CI analysis: `isRunning`, `hasFailed`, `allPassed`, `summary` |
187
+ | `Logger` | Logging interface (`info`, `error`) |
163
188
 
164
189
  ## Appendix
165
190
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/pr-analyzer",
3
- "version": "1.0.73",
3
+ "version": "1.0.74",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -15,7 +15,7 @@
15
15
  "clean": "rm -rf dist"
16
16
  },
17
17
  "dependencies": {
18
- "@hardlydifficult/github": "1.0.33"
18
+ "@hardlydifficult/github": "1.0.34"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "25.3.0",