@aaronshaf/ger 2.0.9 → 3.0.1
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.
- package/README.md +0 -26
- package/docs/prd/architecture.md +6 -48
- package/docs/prd/commands.md +26 -20
- package/index.ts +0 -19
- package/llms.txt +0 -14
- package/package.json +1 -5
- package/src/api/gerrit.ts +23 -33
- package/src/cli/commands/set-ready.ts +76 -0
- package/src/cli/commands/set-wip.ts +76 -0
- package/src/cli/commands/setup.ts +0 -1
- package/src/cli/index.ts +38 -0
- package/src/cli/register-commands.ts +3 -102
- package/src/cli/register-state-commands.ts +106 -0
- package/src/utils/diff-formatters.ts +32 -0
- package/src/cli/commands/review.ts +0 -486
- package/src/prompts/default-review.md +0 -86
- package/src/prompts/system-inline-review.md +0 -135
- package/src/prompts/system-overall-review.md +0 -206
- package/src/services/review-strategy.ts +0 -292
package/README.md
CHANGED
|
@@ -93,9 +93,6 @@ ger rebase 12345
|
|
|
93
93
|
ger submit 12345
|
|
94
94
|
ger restore 12345
|
|
95
95
|
|
|
96
|
-
# AI-powered code review (requires claude, llm, or opencode CLI)
|
|
97
|
-
ger review 12345
|
|
98
|
-
ger review 12345 --dry-run # Preview without posting
|
|
99
96
|
```
|
|
100
97
|
|
|
101
98
|
## Commands
|
|
@@ -711,29 +708,6 @@ ger groups-members project-reviewers --xml
|
|
|
711
708
|
- Group IDs can be names, numeric IDs, or UUIDs
|
|
712
709
|
- Use groups with `ger add-reviewer --group` to add entire teams as reviewers
|
|
713
710
|
|
|
714
|
-
### AI-Powered Review
|
|
715
|
-
|
|
716
|
-
The `ger review` command provides automated code review using AI tools (claude, llm, or opencode CLI).
|
|
717
|
-
|
|
718
|
-
```bash
|
|
719
|
-
# Full AI review with inline and overall comments
|
|
720
|
-
ger review 12345
|
|
721
|
-
|
|
722
|
-
# Preview what would be posted without actually posting
|
|
723
|
-
ger review 12345 --dry-run
|
|
724
|
-
|
|
725
|
-
# Show debug output including AI responses
|
|
726
|
-
ger review 12345 --debug
|
|
727
|
-
```
|
|
728
|
-
|
|
729
|
-
The review command performs a two-stage review process:
|
|
730
|
-
1. **Inline comments**: Specific code issues with line-by-line feedback
|
|
731
|
-
2. **Overall review**: High-level assessment and recommendations
|
|
732
|
-
|
|
733
|
-
Requirements:
|
|
734
|
-
- One of these AI tools must be installed: `claude`, `llm`, or `opencode`
|
|
735
|
-
- Gerrit credentials must be configured (`ger setup`)
|
|
736
|
-
|
|
737
711
|
## Claude Code Skill
|
|
738
712
|
|
|
739
713
|
This repository includes a Claude Code Agent Skill that teaches Claude how to work effectively with Gerrit using the ger CLI. The skill provides Claude with expertise in Gerrit workflows, command usage, and best practices.
|
package/docs/prd/architecture.md
CHANGED
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
┌─────────────────────────────────────────────────────────────┐
|
|
7
7
|
│ CLI Layer │
|
|
8
8
|
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
|
9
|
-
│ │ show │ │ comment │ │ push │ │
|
|
9
|
+
│ │ show │ │ comment │ │ push │ │ vote │ ... │
|
|
10
10
|
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
|
11
11
|
└───────┼───────────┼───────────┼───────────┼─────────────────┘
|
|
12
12
|
│ │ │ │
|
|
13
13
|
┌───────┴───────────┴───────────┴───────────┴─────────────────┐
|
|
14
14
|
│ Service Layer │
|
|
15
|
-
│ ┌──────────────┐ ┌──────────────┐
|
|
16
|
-
│ │ GerritApi │ │ ConfigService│
|
|
17
|
-
│ │ Service │ │ │
|
|
18
|
-
│ └──────────────┘ └──────────────┘
|
|
15
|
+
│ ┌──────────────┐ ┌──────────────┐ │
|
|
16
|
+
│ │ GerritApi │ │ ConfigService│ │
|
|
17
|
+
│ │ Service │ │ │ │
|
|
18
|
+
│ └──────────────┘ └──────────────┘ │
|
|
19
19
|
└───────┬───────────────────────────────────────────────────────┘
|
|
20
20
|
│
|
|
21
21
|
┌───────┴─────────────────────────────────────────────────────┐
|
|
@@ -46,7 +46,6 @@ src/
|
|
|
46
46
|
│
|
|
47
47
|
├── services/ # Business logic services
|
|
48
48
|
│ ├── config.ts # Configuration management
|
|
49
|
-
│ ├── review-strategy.ts # AI tool strategies
|
|
50
49
|
│ ├── git-worktree.ts # Git worktree operations
|
|
51
50
|
│ └── commit-hook.ts # Gerrit hook installation
|
|
52
51
|
│
|
|
@@ -59,12 +58,7 @@ src/
|
|
|
59
58
|
│ ├── git-commit.ts # Git operations
|
|
60
59
|
│ ├── formatters.ts # Output formatting
|
|
61
60
|
│ ├── shell-safety.ts # XML/CDATA handling
|
|
62
|
-
│ └── ... (diff, comment
|
|
63
|
-
│
|
|
64
|
-
├── prompts/ # AI review prompts
|
|
65
|
-
│ ├── default-review.md
|
|
66
|
-
│ ├── system-inline-review.md
|
|
67
|
-
│ └── system-overall-review.md
|
|
61
|
+
│ └── ... (diff, comment utils)
|
|
68
62
|
│
|
|
69
63
|
└── i18n/ # Internationalization (planned)
|
|
70
64
|
|
|
@@ -207,42 +201,6 @@ User: echo '...' | ger comment 12345
|
|
|
207
201
|
Success/Error
|
|
208
202
|
```
|
|
209
203
|
|
|
210
|
-
## AI Integration Flow
|
|
211
|
-
|
|
212
|
-
```
|
|
213
|
-
User: ger review 12345
|
|
214
|
-
│
|
|
215
|
-
▼
|
|
216
|
-
┌─────────────────────┐
|
|
217
|
-
│ Fetch change diff │
|
|
218
|
-
│ (API: GET /patch) │
|
|
219
|
-
└─────────┬───────────┘
|
|
220
|
-
│
|
|
221
|
-
▼
|
|
222
|
-
┌─────────────────────┐
|
|
223
|
-
│ Detect AI tool │
|
|
224
|
-
│ (claude/llm/etc) │
|
|
225
|
-
└─────────┬───────────┘
|
|
226
|
-
│
|
|
227
|
-
▼
|
|
228
|
-
┌─────────────────────┐ ┌─────────────────────┐
|
|
229
|
-
│ Stage 1: Inline │────►│ AI: Generate inline │
|
|
230
|
-
│ comments │ │ comments JSON │
|
|
231
|
-
└─────────┬───────────┘ └─────────────────────┘
|
|
232
|
-
│
|
|
233
|
-
▼
|
|
234
|
-
┌─────────────────────┐ ┌─────────────────────┐
|
|
235
|
-
│ Stage 2: Overall │────►│ AI: Generate │
|
|
236
|
-
│ review │ │ summary │
|
|
237
|
-
└─────────┬───────────┘ └─────────────────────┘
|
|
238
|
-
│
|
|
239
|
-
▼
|
|
240
|
-
┌─────────────────────┐
|
|
241
|
-
│ API: POST /review │
|
|
242
|
-
│ (all comments) │
|
|
243
|
-
└─────────────────────┘
|
|
244
|
-
```
|
|
245
|
-
|
|
246
204
|
## Configuration Architecture
|
|
247
205
|
|
|
248
206
|
```
|
package/docs/prd/commands.md
CHANGED
|
@@ -121,6 +121,32 @@ ger restore <change-id>
|
|
|
121
121
|
ger restore <change-id> -m "Needed after all"
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
### set-ready
|
|
125
|
+
|
|
126
|
+
Mark a WIP change as ready for review via the Gerrit REST API. Does not require a git push.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
ger set-ready <change-id>
|
|
130
|
+
ger set-ready <change-id> -m "Ready for another look"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
| Option | Description |
|
|
134
|
+
|--------|-------------|
|
|
135
|
+
| `-m <message>` | Optional message to include with the status change |
|
|
136
|
+
|
|
137
|
+
### set-wip
|
|
138
|
+
|
|
139
|
+
Mark a change as work-in-progress via the Gerrit REST API. Does not require a git push.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
ger set-wip <change-id>
|
|
143
|
+
ger set-wip <change-id> -m "Still in progress"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
| Option | Description |
|
|
147
|
+
|--------|-------------|
|
|
148
|
+
| `-m <message>` | Optional message to include with the status change |
|
|
149
|
+
|
|
124
150
|
### workspace
|
|
125
151
|
|
|
126
152
|
View local git branch tracking information.
|
|
@@ -236,26 +262,6 @@ ger vote <change-id> --label "Custom-Label" +1
|
|
|
236
262
|
| `--label <name> <score>` | Custom label vote |
|
|
237
263
|
| `-m <message>` | Optional message with vote |
|
|
238
264
|
|
|
239
|
-
### review
|
|
240
|
-
|
|
241
|
-
AI-powered code review (multi-stage).
|
|
242
|
-
|
|
243
|
-
```bash
|
|
244
|
-
ger review <change-id>
|
|
245
|
-
ger review <change-id> --tool claude # Specific AI tool
|
|
246
|
-
ger review # Auto-detect change from HEAD
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
| Option | Description |
|
|
250
|
-
|--------|-------------|
|
|
251
|
-
| `--tool <name>` | AI tool (claude, llm, opencode, gemini) |
|
|
252
|
-
| `--inline-only` | Only post inline comments |
|
|
253
|
-
| `--overall-only` | Only post overall review |
|
|
254
|
-
|
|
255
|
-
**Stages:**
|
|
256
|
-
1. **Inline**: Generate line-specific comments
|
|
257
|
-
2. **Overall**: Generate high-level assessment
|
|
258
|
-
|
|
259
265
|
### add-reviewer
|
|
260
266
|
|
|
261
267
|
Add reviewers or groups to a change.
|
package/index.ts
CHANGED
|
@@ -61,25 +61,6 @@ export {
|
|
|
61
61
|
type ConfigErrorFields,
|
|
62
62
|
} from './src/services/config'
|
|
63
63
|
|
|
64
|
-
// ============================================================================
|
|
65
|
-
// Review Strategy Service
|
|
66
|
-
// ============================================================================
|
|
67
|
-
|
|
68
|
-
export {
|
|
69
|
-
// Strategy types
|
|
70
|
-
type ReviewStrategy,
|
|
71
|
-
// Built-in strategies
|
|
72
|
-
claudeCliStrategy,
|
|
73
|
-
geminiCliStrategy,
|
|
74
|
-
openCodeCliStrategy,
|
|
75
|
-
// Service
|
|
76
|
-
ReviewStrategyService,
|
|
77
|
-
ReviewStrategyServiceLive,
|
|
78
|
-
type ReviewStrategyServiceImpl,
|
|
79
|
-
// Errors
|
|
80
|
-
ReviewStrategyError,
|
|
81
|
-
type ReviewStrategyErrorFields,
|
|
82
|
-
} from './src/services/review-strategy'
|
|
83
64
|
|
|
84
65
|
// ============================================================================
|
|
85
66
|
// Git Worktree Service
|
package/llms.txt
CHANGED
|
@@ -114,14 +114,6 @@ ger extract-url "build-summary-report" | tail -1 # Latest Jenkins URL
|
|
|
114
114
|
ger extract-url "jenkins" --json | jq -r '.urls[-1]'
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
### AI Review
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
ger review <change-id> # AI-powered review (requires claude/gemini/opencode CLI)
|
|
121
|
-
ger review <change-id> --tool claude
|
|
122
|
-
ger review <change-id> --comment --yes # Post review comments
|
|
123
|
-
```
|
|
124
|
-
|
|
125
117
|
### Groups
|
|
126
118
|
|
|
127
119
|
```bash
|
|
@@ -179,12 +171,6 @@ ger comment 12345 -m "LGTM" # Add comment
|
|
|
179
171
|
ger vote 12345 --code-review +2 # Approve
|
|
180
172
|
```
|
|
181
173
|
|
|
182
|
-
### Post AI review
|
|
183
|
-
|
|
184
|
-
```bash
|
|
185
|
-
ger review 12345 --comment --yes
|
|
186
|
-
```
|
|
187
|
-
|
|
188
174
|
### Check build and get failures
|
|
189
175
|
|
|
190
176
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aaronshaf/ger",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Gerrit CLI and SDK - A modern CLI tool and TypeScript SDK for Gerrit Code Review, built with Effect-TS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gerrit",
|
|
@@ -30,10 +30,6 @@
|
|
|
30
30
|
"import": "./src/services/config.ts",
|
|
31
31
|
"types": "./src/services/config.ts"
|
|
32
32
|
},
|
|
33
|
-
"./services/review-strategy": {
|
|
34
|
-
"import": "./src/services/review-strategy.ts",
|
|
35
|
-
"types": "./src/services/review-strategy.ts"
|
|
36
|
-
},
|
|
37
33
|
"./services/git-worktree": {
|
|
38
34
|
"import": "./src/services/git-worktree.ts",
|
|
39
35
|
"types": "./src/services/git-worktree.ts"
|
package/src/api/gerrit.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
AccountInfo,
|
|
20
20
|
} from '@/schemas/gerrit'
|
|
21
21
|
import { filterMeaningfulMessages } from '@/utils/message-filters'
|
|
22
|
+
import { convertToUnifiedDiff } from '@/utils/diff-formatters'
|
|
22
23
|
import { ConfigService } from '@/services/config'
|
|
23
24
|
import { normalizeChangeIdentifier } from '@/utils/change-id'
|
|
24
25
|
|
|
@@ -93,6 +94,8 @@ export interface GerritApiServiceImpl {
|
|
|
93
94
|
readonly getTopic: (changeId: string) => Effect.Effect<string | null, ApiError>
|
|
94
95
|
readonly setTopic: (changeId: string, topic: string) => Effect.Effect<string, ApiError>
|
|
95
96
|
readonly deleteTopic: (changeId: string) => Effect.Effect<void, ApiError>
|
|
97
|
+
readonly setReady: (changeId: string, message?: string) => Effect.Effect<void, ApiError>
|
|
98
|
+
readonly setWip: (changeId: string, message?: string) => Effect.Effect<void, ApiError>
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
export const GerritApiService: Context.Tag<GerritApiServiceImpl, GerritApiServiceImpl> =
|
|
@@ -455,39 +458,6 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
455
458
|
return yield* getPatch(changeId, revisionId)
|
|
456
459
|
})
|
|
457
460
|
|
|
458
|
-
const convertToUnifiedDiff = (diff: FileDiffContent, filePath: string): string => {
|
|
459
|
-
const lines: string[] = []
|
|
460
|
-
|
|
461
|
-
if (diff.diff_header) {
|
|
462
|
-
lines.push(...diff.diff_header)
|
|
463
|
-
} else {
|
|
464
|
-
lines.push(`--- a/${filePath}`)
|
|
465
|
-
lines.push(`+++ b/${filePath}`)
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
for (const section of diff.content) {
|
|
469
|
-
if (section.ab) {
|
|
470
|
-
for (const line of section.ab) {
|
|
471
|
-
lines.push(` ${line}`)
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if (section.a) {
|
|
476
|
-
for (const line of section.a) {
|
|
477
|
-
lines.push(`-${line}`)
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
if (section.b) {
|
|
482
|
-
for (const line of section.b) {
|
|
483
|
-
lines.push(`+${line}`)
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
return lines.join('\n')
|
|
489
|
-
}
|
|
490
|
-
|
|
491
461
|
const getComments = (changeId: string, revisionId = 'current') =>
|
|
492
462
|
Effect.gen(function* () {
|
|
493
463
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
@@ -667,6 +637,24 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
667
637
|
yield* makeRequest(getTopicUrl(credentials.host, normalized), authHeader, 'DELETE')
|
|
668
638
|
})
|
|
669
639
|
|
|
640
|
+
const setReady = (changeId: string, message?: string) =>
|
|
641
|
+
Effect.gen(function* () {
|
|
642
|
+
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
643
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
644
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/ready`
|
|
645
|
+
const body = message ? { message } : {}
|
|
646
|
+
yield* makeRequest(url, authHeader, 'POST', body)
|
|
647
|
+
})
|
|
648
|
+
|
|
649
|
+
const setWip = (changeId: string, message?: string) =>
|
|
650
|
+
Effect.gen(function* () {
|
|
651
|
+
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
652
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
653
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/wip`
|
|
654
|
+
const body = message ? { message } : {}
|
|
655
|
+
yield* makeRequest(url, authHeader, 'POST', body)
|
|
656
|
+
})
|
|
657
|
+
|
|
670
658
|
return {
|
|
671
659
|
getChange,
|
|
672
660
|
listChanges,
|
|
@@ -694,6 +682,8 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
694
682
|
getTopic,
|
|
695
683
|
setTopic,
|
|
696
684
|
deleteTopic,
|
|
685
|
+
setReady,
|
|
686
|
+
setWip,
|
|
697
687
|
}
|
|
698
688
|
}),
|
|
699
689
|
)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Effect } from 'effect'
|
|
2
|
+
import { type ApiError, GerritApiService } from '@/api/gerrit'
|
|
3
|
+
import { sanitizeCDATA } from '@/utils/shell-safety'
|
|
4
|
+
|
|
5
|
+
interface SetReadyOptions {
|
|
6
|
+
message?: string
|
|
7
|
+
xml?: boolean
|
|
8
|
+
json?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const setReadyCommand = (
|
|
12
|
+
changeId?: string,
|
|
13
|
+
options: SetReadyOptions = {},
|
|
14
|
+
): Effect.Effect<void, ApiError, GerritApiService> =>
|
|
15
|
+
Effect.gen(function* () {
|
|
16
|
+
const gerritApi = yield* GerritApiService
|
|
17
|
+
|
|
18
|
+
if (!changeId) {
|
|
19
|
+
console.error('✗ Change ID is required')
|
|
20
|
+
console.error(' Usage: ger set-ready <change-id>')
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Try to fetch change details for richer output, but don't let it block the mutation
|
|
25
|
+
let changeNumber: number | undefined
|
|
26
|
+
let subject: string | undefined
|
|
27
|
+
try {
|
|
28
|
+
const change = yield* gerritApi.getChange(changeId)
|
|
29
|
+
changeNumber = change._number
|
|
30
|
+
subject = change.subject
|
|
31
|
+
} catch {
|
|
32
|
+
// Proceed without change details
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
yield* gerritApi.setReady(changeId, options.message)
|
|
36
|
+
|
|
37
|
+
if (options.json) {
|
|
38
|
+
console.log(
|
|
39
|
+
JSON.stringify(
|
|
40
|
+
{
|
|
41
|
+
status: 'success',
|
|
42
|
+
...(changeNumber !== undefined
|
|
43
|
+
? { change_number: changeNumber }
|
|
44
|
+
: { change_id: changeId }),
|
|
45
|
+
...(subject !== undefined ? { subject } : {}),
|
|
46
|
+
...(options.message ? { message: options.message } : {}),
|
|
47
|
+
},
|
|
48
|
+
null,
|
|
49
|
+
2,
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
} else if (options.xml) {
|
|
53
|
+
console.log(`<?xml version="1.0" encoding="UTF-8"?>`)
|
|
54
|
+
console.log(`<set_ready_result>`)
|
|
55
|
+
console.log(` <status>success</status>`)
|
|
56
|
+
if (changeNumber !== undefined) {
|
|
57
|
+
console.log(` <change_number>${changeNumber}</change_number>`)
|
|
58
|
+
} else {
|
|
59
|
+
console.log(` <change_id>${changeId}</change_id>`)
|
|
60
|
+
}
|
|
61
|
+
if (subject !== undefined) {
|
|
62
|
+
console.log(` <subject><![CDATA[${sanitizeCDATA(subject)}]]></subject>`)
|
|
63
|
+
}
|
|
64
|
+
if (options.message) {
|
|
65
|
+
console.log(` <message><![CDATA[${sanitizeCDATA(options.message)}]]></message>`)
|
|
66
|
+
}
|
|
67
|
+
console.log(`</set_ready_result>`)
|
|
68
|
+
} else {
|
|
69
|
+
const label = changeNumber !== undefined ? `${changeNumber}` : changeId
|
|
70
|
+
const suffix = subject !== undefined ? `: ${subject}` : ''
|
|
71
|
+
console.log(`✓ Marked change ${label} as ready for review${suffix}`)
|
|
72
|
+
if (options.message) {
|
|
73
|
+
console.log(` Message: ${options.message}`)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Effect } from 'effect'
|
|
2
|
+
import { type ApiError, GerritApiService } from '@/api/gerrit'
|
|
3
|
+
import { sanitizeCDATA } from '@/utils/shell-safety'
|
|
4
|
+
|
|
5
|
+
interface SetWipOptions {
|
|
6
|
+
message?: string
|
|
7
|
+
xml?: boolean
|
|
8
|
+
json?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const setWipCommand = (
|
|
12
|
+
changeId?: string,
|
|
13
|
+
options: SetWipOptions = {},
|
|
14
|
+
): Effect.Effect<void, ApiError, GerritApiService> =>
|
|
15
|
+
Effect.gen(function* () {
|
|
16
|
+
const gerritApi = yield* GerritApiService
|
|
17
|
+
|
|
18
|
+
if (!changeId) {
|
|
19
|
+
console.error('✗ Change ID is required')
|
|
20
|
+
console.error(' Usage: ger set-wip <change-id>')
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Try to fetch change details for richer output, but don't let it block the mutation
|
|
25
|
+
let changeNumber: number | undefined
|
|
26
|
+
let subject: string | undefined
|
|
27
|
+
try {
|
|
28
|
+
const change = yield* gerritApi.getChange(changeId)
|
|
29
|
+
changeNumber = change._number
|
|
30
|
+
subject = change.subject
|
|
31
|
+
} catch {
|
|
32
|
+
// Proceed without change details
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
yield* gerritApi.setWip(changeId, options.message)
|
|
36
|
+
|
|
37
|
+
if (options.json) {
|
|
38
|
+
console.log(
|
|
39
|
+
JSON.stringify(
|
|
40
|
+
{
|
|
41
|
+
status: 'success',
|
|
42
|
+
...(changeNumber !== undefined
|
|
43
|
+
? { change_number: changeNumber }
|
|
44
|
+
: { change_id: changeId }),
|
|
45
|
+
...(subject !== undefined ? { subject } : {}),
|
|
46
|
+
...(options.message ? { message: options.message } : {}),
|
|
47
|
+
},
|
|
48
|
+
null,
|
|
49
|
+
2,
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
} else if (options.xml) {
|
|
53
|
+
console.log(`<?xml version="1.0" encoding="UTF-8"?>`)
|
|
54
|
+
console.log(`<set_wip_result>`)
|
|
55
|
+
console.log(` <status>success</status>`)
|
|
56
|
+
if (changeNumber !== undefined) {
|
|
57
|
+
console.log(` <change_number>${changeNumber}</change_number>`)
|
|
58
|
+
} else {
|
|
59
|
+
console.log(` <change_id>${changeId}</change_id>`)
|
|
60
|
+
}
|
|
61
|
+
if (subject !== undefined) {
|
|
62
|
+
console.log(` <subject><![CDATA[${sanitizeCDATA(subject)}]]></subject>`)
|
|
63
|
+
}
|
|
64
|
+
if (options.message) {
|
|
65
|
+
console.log(` <message><![CDATA[${sanitizeCDATA(options.message)}]]></message>`)
|
|
66
|
+
}
|
|
67
|
+
console.log(`</set_wip_result>`)
|
|
68
|
+
} else {
|
|
69
|
+
const label = changeNumber !== undefined ? `${changeNumber}` : changeId
|
|
70
|
+
const suffix = subject !== undefined ? `: ${subject}` : ''
|
|
71
|
+
console.log(`✓ Marked change ${label} as work-in-progress${suffix}`)
|
|
72
|
+
if (options.message) {
|
|
73
|
+
console.log(` Message: ${options.message}`)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
})
|
|
@@ -260,7 +260,6 @@ const setupEffect = (configService: ConfigServiceImpl) =>
|
|
|
260
260
|
Effect.tap(() => Console.log('You can now use:')),
|
|
261
261
|
Effect.tap(() => Console.log(' • "ger mine" to view your changes')),
|
|
262
262
|
Effect.tap(() => Console.log(' • "ger show <change-id>" to view change details')),
|
|
263
|
-
Effect.tap(() => Console.log(' • "ger review <change-id>" to review with AI')),
|
|
264
263
|
Effect.catchAll((error) =>
|
|
265
264
|
pipe(
|
|
266
265
|
Console.error(
|
package/src/cli/index.ts
CHANGED
|
@@ -48,6 +48,44 @@ const program = new Command()
|
|
|
48
48
|
|
|
49
49
|
program.name('ger').description('LLM-centric Gerrit CLI tool').version(getVersion())
|
|
50
50
|
|
|
51
|
+
program.addHelpText(
|
|
52
|
+
'after',
|
|
53
|
+
`
|
|
54
|
+
CHANGE-ID FORMATS
|
|
55
|
+
Accepts numeric change numbers (12345) or full Change-IDs (I1234abc...).
|
|
56
|
+
Many commands auto-detect from HEAD commit's Change-Id footer when the
|
|
57
|
+
argument is omitted.
|
|
58
|
+
|
|
59
|
+
OUTPUT FORMATS
|
|
60
|
+
--json Structured JSON output for programmatic consumption
|
|
61
|
+
--xml XML with CDATA-wrapped content, optimized for LLM consumption
|
|
62
|
+
(default) Plain text for human reading
|
|
63
|
+
Most commands support both --json and --xml.
|
|
64
|
+
|
|
65
|
+
PIPING / STDIN
|
|
66
|
+
comment Reads message from stdin if no -m flag is provided
|
|
67
|
+
comment --batch Reads a JSON array from stdin for bulk commenting
|
|
68
|
+
|
|
69
|
+
AUTO-DETECTION
|
|
70
|
+
These commands auto-detect the change from HEAD's Change-Id footer when
|
|
71
|
+
the change-id argument is omitted:
|
|
72
|
+
show, build-status, topic, rebase, extract-url, diff, comments, vote
|
|
73
|
+
|
|
74
|
+
COMMON LLM WORKFLOWS
|
|
75
|
+
Review a change: ger show <id> → ger diff <id> → ger comments <id>
|
|
76
|
+
Post a review: ger comment <id> -m "..." → ger vote <id> <label> <score>
|
|
77
|
+
Manage changes: ger push, ger checkout <id>, ger abandon <id>, ger submit <id>
|
|
78
|
+
WIP toggle: ger set-wip <id>, ger set-ready <id> [-m "message"]
|
|
79
|
+
Check CI: ger build-status <id> --exit-status
|
|
80
|
+
|
|
81
|
+
EXIT CODES
|
|
82
|
+
build-status --exit-status returns non-zero on build failure (useful for scripting).
|
|
83
|
+
|
|
84
|
+
SUBCOMMAND HELP
|
|
85
|
+
Run ger <command> --help for detailed usage and examples.
|
|
86
|
+
`,
|
|
87
|
+
)
|
|
88
|
+
|
|
51
89
|
registerCommands(program)
|
|
52
90
|
|
|
53
91
|
program.parse(process.argv)
|