@aaronshaf/ger 0.1.10 → 0.2.0
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/.github/workflows/claude-code-review.yml +61 -56
- package/.github/workflows/claude.yml +10 -24
- package/README.md +53 -6
- package/bun.lock +8 -8
- package/package.json +3 -3
- package/src/api/gerrit.ts +54 -16
- package/src/cli/commands/extract-url.ts +266 -0
- package/src/cli/commands/review.ts +13 -2
- package/src/cli/commands/setup.ts +1 -1
- package/src/cli/commands/show.ts +112 -18
- package/src/cli/index.ts +140 -23
- package/src/schemas/config.ts +13 -4
- package/src/services/config.test.ts +150 -0
- package/src/services/config.ts +60 -16
- package/src/services/git-worktree.ts +73 -16
- package/src/services/review-strategy.ts +40 -22
- package/src/utils/change-id.test.ts +98 -0
- package/src/utils/change-id.ts +63 -0
- package/src/utils/git-commit.test.ts +277 -0
- package/src/utils/git-commit.ts +122 -0
- package/tests/change-id-formats.test.ts +268 -0
- package/tests/extract-url.test.ts +518 -0
- package/tests/mocks/fetch-mock.ts +5 -2
- package/tests/mocks/msw-handlers.ts +3 -3
- package/tests/show-auto-detect.test.ts +306 -0
- package/tests/show.test.ts +157 -1
- package/tests/unit/git-worktree.test.ts +2 -1
- package/tsconfig.json +2 -1
|
@@ -2,77 +2,82 @@ name: Claude Code Review
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
pull_request:
|
|
5
|
-
types: [opened, synchronize]
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
types: [opened, synchronize, ready_for_review, reopened]
|
|
6
|
+
paths:
|
|
7
|
+
- "src/**/*.ts"
|
|
8
|
+
- "tests/**/*.ts"
|
|
9
|
+
- "scripts/**/*.ts"
|
|
10
|
+
- "package.json"
|
|
11
|
+
- "tsconfig.json"
|
|
12
12
|
|
|
13
13
|
jobs:
|
|
14
14
|
claude-review:
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
# Skip draft PRs and PRs from bots
|
|
16
|
+
if: |
|
|
17
|
+
github.event.pull_request.draft == false &&
|
|
18
|
+
github.event.pull_request.user.login != 'dependabot[bot]'
|
|
19
|
+
|
|
21
20
|
runs-on: ubuntu-latest
|
|
22
21
|
permissions:
|
|
23
22
|
contents: read
|
|
24
|
-
pull-requests:
|
|
25
|
-
issues: read
|
|
23
|
+
pull-requests: write
|
|
26
24
|
id-token: write
|
|
27
|
-
|
|
25
|
+
|
|
28
26
|
steps:
|
|
29
27
|
- name: Checkout repository
|
|
30
|
-
uses: actions/checkout@
|
|
28
|
+
uses: actions/checkout@v5
|
|
31
29
|
with:
|
|
32
30
|
fetch-depth: 1
|
|
33
31
|
|
|
34
32
|
- name: Run Claude Code Review
|
|
35
33
|
id: claude-review
|
|
36
|
-
uses: anthropics/claude-code-action@
|
|
34
|
+
uses: anthropics/claude-code-action@v1
|
|
37
35
|
with:
|
|
38
36
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
39
37
|
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
38
|
+
# Enable progress tracking for sticky comments
|
|
39
|
+
track_progress: true
|
|
40
|
+
|
|
41
|
+
prompt: |
|
|
42
|
+
REPO: ${{ github.repository }}
|
|
43
|
+
PR NUMBER: ${{ github.event.pull_request.number }}
|
|
44
|
+
|
|
45
|
+
Perform a comprehensive code review focusing on:
|
|
46
|
+
|
|
47
|
+
1. **Code Quality & Standards**
|
|
48
|
+
- Adherence to CLAUDE.md project rules
|
|
49
|
+
- TypeScript best practices with isolatedDeclarations
|
|
50
|
+
- No implicit any or as typecasting (except as const/as unknown)
|
|
51
|
+
- Functional programming patterns with Effect
|
|
52
|
+
- Files should not exceed 700 lines (block) or 500 lines (warn)
|
|
53
|
+
|
|
54
|
+
2. **Testing & Coverage**
|
|
55
|
+
- Minimum 80% code coverage requirement
|
|
56
|
+
- Both unit tests and integration tests for command changes
|
|
57
|
+
- Proper HTTP mocking with Bun's native fetch
|
|
58
|
+
- Effect Schema validation in tests
|
|
59
|
+
|
|
60
|
+
3. **Security**
|
|
61
|
+
- No sensitive data in code or error messages
|
|
62
|
+
- Effect Schema validation for all inputs
|
|
63
|
+
- SQL injection prevention
|
|
64
|
+
|
|
65
|
+
4. **Architecture & Patterns**
|
|
66
|
+
- Effect services implementation
|
|
67
|
+
- Cache-first strategy with SQLite
|
|
68
|
+
- Regional error boundaries
|
|
69
|
+
- Proper i18n with i18next
|
|
70
|
+
|
|
71
|
+
5. **Performance**
|
|
72
|
+
- Efficient caching strategies
|
|
73
|
+
- Minimized API calls
|
|
74
|
+
- Bundle size optimization
|
|
75
|
+
|
|
76
|
+
Provide detailed feedback using inline comments for specific issues.
|
|
77
|
+
Use top-level comments for general observations.
|
|
78
|
+
Reference file:line_number for all findings.
|
|
79
|
+
|
|
80
|
+
# Tools for comprehensive PR review with inline comments
|
|
81
|
+
claude_args: |
|
|
82
|
+
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"
|
|
78
83
|
|
|
@@ -32,33 +32,19 @@ jobs:
|
|
|
32
32
|
|
|
33
33
|
- name: Run Claude Code
|
|
34
34
|
id: claude
|
|
35
|
-
uses: anthropics/claude-code-action@
|
|
35
|
+
uses: anthropics/claude-code-action@v1
|
|
36
36
|
with:
|
|
37
37
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
# This is an optional setting that allows Claude to read CI results on PRs
|
|
40
40
|
additional_permissions: |
|
|
41
41
|
actions: read
|
|
42
|
-
|
|
43
|
-
# Optional:
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
# Optional:
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
#
|
|
50
|
-
# assignee_trigger: "claude-bot"
|
|
51
|
-
|
|
52
|
-
# Optional: Allow Claude to run specific commands
|
|
53
|
-
# allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
|
|
54
|
-
|
|
55
|
-
# Optional: Add custom instructions for Claude to customize its behavior for your project
|
|
56
|
-
# custom_instructions: |
|
|
57
|
-
# Follow our coding standards
|
|
58
|
-
# Ensure all new code has tests
|
|
59
|
-
# Use TypeScript for new files
|
|
60
|
-
|
|
61
|
-
# Optional: Custom environment variables for Claude
|
|
62
|
-
# claude_env: |
|
|
63
|
-
# NODE_ENV: test
|
|
42
|
+
|
|
43
|
+
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
|
44
|
+
# prompt: 'Update the pull request description to include a summary of changes.'
|
|
45
|
+
|
|
46
|
+
# Optional: Add claude_args to customize behavior and configuration
|
|
47
|
+
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
|
48
|
+
# or https://docs.anthropic.com/en/docs/claude-code/sdk#command-line for available options
|
|
49
|
+
# claude_args: '--model claude-opus-4-1-20250805 --allowed-tools Bash(gh pr:*)'
|
|
64
50
|
|
package/README.md
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
# ger
|
|
2
2
|
|
|
3
|
-
Gerrit CLI built with Bun.
|
|
3
|
+
Gerrit CLI built with Bun.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **LLM-Friendly**: XML output for AI/automation pipelines
|
|
8
|
-
- **Interactive UI**: Terminal UI for change selection and navigation
|
|
9
|
-
- **Secure**: Credentials stored in system keychain
|
|
8
|
+
- **Interactive UI**: Terminal UI for change selection and navigation
|
|
10
9
|
- **Effect-based**: Robust error handling and functional architecture
|
|
11
|
-
- **Batch Comments**: JSON array input with line/range targeting and side support
|
|
12
10
|
|
|
13
11
|
## Installation
|
|
14
12
|
|
|
@@ -31,8 +29,6 @@ This will prompt for your Gerrit credentials:
|
|
|
31
29
|
- Username
|
|
32
30
|
- HTTP password (from Gerrit settings)
|
|
33
31
|
|
|
34
|
-
Credentials are securely stored in your system keychain.
|
|
35
|
-
|
|
36
32
|
## Common Commands
|
|
37
33
|
|
|
38
34
|
### Daily Workflow
|
|
@@ -56,6 +52,9 @@ ger comment 12345 -m "LGTM"
|
|
|
56
52
|
# Get diff for review
|
|
57
53
|
ger diff 12345
|
|
58
54
|
|
|
55
|
+
# Extract URLs from messages (e.g., Jenkins build links)
|
|
56
|
+
ger extract-url "build-summary-report" | tail -1
|
|
57
|
+
|
|
59
58
|
# AI-powered code review (requires claude, llm, or opencode CLI)
|
|
60
59
|
ger review 12345
|
|
61
60
|
ger review 12345 --dry-run # Preview without posting
|
|
@@ -195,6 +194,54 @@ ger comments 12345
|
|
|
195
194
|
ger comments 12345 --pretty
|
|
196
195
|
```
|
|
197
196
|
|
|
197
|
+
### Extract URLs
|
|
198
|
+
|
|
199
|
+
Extract URLs from change messages and comments for automation and scripting:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Extract all Jenkins build-summary-report URLs
|
|
203
|
+
ger extract-url "build-summary-report"
|
|
204
|
+
|
|
205
|
+
# Get the latest build URL (using tail)
|
|
206
|
+
ger extract-url "build-summary-report" | tail -1
|
|
207
|
+
|
|
208
|
+
# Get the first/oldest build URL (using head)
|
|
209
|
+
ger extract-url "jenkins" | head -1
|
|
210
|
+
|
|
211
|
+
# For a specific change
|
|
212
|
+
ger extract-url "build-summary" 12345
|
|
213
|
+
|
|
214
|
+
# Use regex for precise matching
|
|
215
|
+
ger extract-url "job/Canvas/job/main/\d+/" --regex
|
|
216
|
+
|
|
217
|
+
# Search both messages and inline comments
|
|
218
|
+
ger extract-url "github.com" --include-comments
|
|
219
|
+
|
|
220
|
+
# JSON output for scripting
|
|
221
|
+
ger extract-url "jenkins" --json | jq -r '.urls[-1]'
|
|
222
|
+
|
|
223
|
+
# XML output
|
|
224
|
+
ger extract-url "jenkins" --xml
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### How it works:
|
|
228
|
+
- **Pattern matching**: Substring match by default, regex with `--regex`
|
|
229
|
+
- **Sources**: Searches messages by default, add `--include-comments` to include inline comments
|
|
230
|
+
- **Ordering**: URLs are output in chronological order (oldest first)
|
|
231
|
+
- **Composable**: Pipe to `tail -1` for latest, `head -1` for oldest
|
|
232
|
+
|
|
233
|
+
#### Common use cases:
|
|
234
|
+
```bash
|
|
235
|
+
# Get latest Jenkins build URL for a change
|
|
236
|
+
ger extract-url "jenkins.inst-ci.net" | tail -1
|
|
237
|
+
|
|
238
|
+
# Find all GitHub PR references
|
|
239
|
+
ger extract-url "github.com" --include-comments
|
|
240
|
+
|
|
241
|
+
# Extract specific build job URLs with regex
|
|
242
|
+
ger extract-url "job/[^/]+/job/[^/]+/\d+/$" --regex
|
|
243
|
+
```
|
|
244
|
+
|
|
198
245
|
### Diff
|
|
199
246
|
```bash
|
|
200
247
|
# Full diff
|
package/bun.lock
CHANGED
|
@@ -4,25 +4,25 @@
|
|
|
4
4
|
"": {
|
|
5
5
|
"name": "ger",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@effect/platform": "^0.90.
|
|
7
|
+
"@effect/platform": "^0.90.10",
|
|
8
8
|
"@effect/platform-node": "^0.94.2",
|
|
9
9
|
"@effect/schema": "^0.75.5",
|
|
10
10
|
"@inquirer/prompts": "^7.8.4",
|
|
11
11
|
"chalk": "^5.6.0",
|
|
12
12
|
"cli-table3": "^0.6.5",
|
|
13
13
|
"commander": "^14.0.0",
|
|
14
|
-
"effect": "^3.
|
|
14
|
+
"effect": "^3.18.4",
|
|
15
15
|
"signal-exit": "3.0.7",
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@biomejs/biome": "^2.2.2",
|
|
19
|
-
"@types/node": "^24.3.
|
|
19
|
+
"@types/node": "^24.3.1",
|
|
20
20
|
"ast-grep": "^0.1.0",
|
|
21
21
|
"bun-types": "^1.2.21",
|
|
22
22
|
"husky": "^9.1.7",
|
|
23
|
-
"lint-staged": "^16.1.
|
|
24
|
-
"msw": "^2.
|
|
25
|
-
"oxlint": "^1.
|
|
23
|
+
"lint-staged": "^16.1.6",
|
|
24
|
+
"msw": "^2.11.1",
|
|
25
|
+
"oxlint": "^1.14.0",
|
|
26
26
|
"typescript": "^5.9.2",
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
|
|
78
78
|
"@effect/experimental": ["@effect/experimental@0.54.6", "", { "dependencies": { "uuid": "^11.0.3" }, "peerDependencies": { "@effect/platform": "^0.90.2", "effect": "^3.17.7", "ioredis": "^5", "lmdb": "^3" }, "optionalPeers": ["ioredis", "lmdb"] }, "sha512-UqHMvCQmrZT6kUVoUC0lqyno4Yad+j9hBGCdUjW84zkLwAq08tPqySiZUKRwY+Ae5B2Ab8rISYJH7nQvct9DMQ=="],
|
|
79
79
|
|
|
80
|
-
"@effect/platform": ["@effect/platform@0.90.
|
|
80
|
+
"@effect/platform": ["@effect/platform@0.90.10", "", { "dependencies": { "find-my-way-ts": "^0.1.6", "msgpackr": "^1.11.4", "multipasta": "^0.2.7" }, "peerDependencies": { "effect": "^3.17.13" } }, "sha512-QhDPgCaLfIMQKOCoCPQvRUS+Y34iYJ07jdZ/CBAvYFvg/iUBebsmFuHL63RCD/YZH9BuK/kqqLYAA3M0fmUEgg=="],
|
|
81
81
|
|
|
82
82
|
"@effect/platform-node": ["@effect/platform-node@0.94.2", "", { "dependencies": { "@effect/platform-node-shared": "^0.47.2", "mime": "^3.0.0", "undici": "^7.10.0", "ws": "^8.18.2" }, "peerDependencies": { "@effect/cluster": "^0.46.4", "@effect/platform": "^0.90.0", "@effect/rpc": "^0.68.3", "@effect/sql": "^0.44.1", "effect": "^3.17.6" } }, "sha512-iI7vUjNqd1DOFCa/9Tyf6Cu00Y4oLKMrpa2lx8+bUIHxtYbk696Yd9VFIDLMXVWrKFUru4Fw7WgWaA/YDor/sw=="],
|
|
83
83
|
|
|
@@ -283,7 +283,7 @@
|
|
|
283
283
|
|
|
284
284
|
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
|
285
285
|
|
|
286
|
-
"effect": ["effect@3.
|
|
286
|
+
"effect": ["effect@3.18.4", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA=="],
|
|
287
287
|
|
|
288
288
|
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
|
289
289
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aaronshaf/ger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"module": "index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"typescript": "^5.0.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@effect/platform": "^0.90.
|
|
32
|
+
"@effect/platform": "^0.90.10",
|
|
33
33
|
"@effect/platform-node": "^0.94.2",
|
|
34
34
|
"@effect/schema": "^0.75.5",
|
|
35
35
|
"@inquirer/prompts": "^7.8.4",
|
|
36
36
|
"chalk": "^5.6.0",
|
|
37
37
|
"cli-table3": "^0.6.5",
|
|
38
38
|
"commander": "^14.0.0",
|
|
39
|
-
"effect": "^3.
|
|
39
|
+
"effect": "^3.18.4",
|
|
40
40
|
"signal-exit": "3.0.7"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
package/src/api/gerrit.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from '@/schemas/gerrit'
|
|
14
14
|
import { filterMeaningfulMessages } from '@/utils/message-filters'
|
|
15
15
|
import { ConfigService } from '@/services/config'
|
|
16
|
+
import { normalizeChangeIdentifier } from '@/utils/change-id'
|
|
16
17
|
|
|
17
18
|
export interface GerritApiServiceImpl {
|
|
18
19
|
readonly getChange: (changeId: string) => Effect.Effect<ChangeInfo, ApiError>
|
|
@@ -51,15 +52,32 @@ export interface GerritApiServiceImpl {
|
|
|
51
52
|
readonly getMessages: (changeId: string) => Effect.Effect<readonly MessageInfo[], ApiError>
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
GerritApiServiceImpl
|
|
57
|
-
>
|
|
55
|
+
// Export both the tag value and the type for use in Effect requirements
|
|
56
|
+
export const GerritApiService: Context.Tag<GerritApiServiceImpl, GerritApiServiceImpl> =
|
|
57
|
+
Context.GenericTag<GerritApiServiceImpl>('GerritApiService')
|
|
58
|
+
export type GerritApiService = Context.Tag.Identifier<typeof GerritApiService>
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
// Export ApiError fields interface explicitly
|
|
61
|
+
export interface ApiErrorFields {
|
|
62
|
+
readonly message: string
|
|
63
|
+
readonly status?: number
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Define error schema (not exported, so type can be implicit)
|
|
67
|
+
const ApiErrorSchema = Schema.TaggedError<ApiErrorFields>()('ApiError', {
|
|
60
68
|
message: Schema.String,
|
|
61
69
|
status: Schema.optional(Schema.Number),
|
|
62
|
-
} as const)
|
|
70
|
+
} as const) as unknown
|
|
71
|
+
|
|
72
|
+
// Export the error class with explicit constructor signature for isolatedDeclarations
|
|
73
|
+
export class ApiError
|
|
74
|
+
extends (ApiErrorSchema as new (
|
|
75
|
+
args: ApiErrorFields,
|
|
76
|
+
) => ApiErrorFields & Error & { readonly _tag: 'ApiError' })
|
|
77
|
+
implements Error
|
|
78
|
+
{
|
|
79
|
+
readonly name = 'ApiError'
|
|
80
|
+
}
|
|
63
81
|
|
|
64
82
|
const createAuthHeader = (credentials: GerritCredentials): string => {
|
|
65
83
|
const auth = btoa(`${credentials.username}:${credentials.password}`)
|
|
@@ -150,10 +168,21 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
150
168
|
return { credentials: normalizedCredentials, authHeader }
|
|
151
169
|
})
|
|
152
170
|
|
|
171
|
+
// Helper to normalize and validate change identifier
|
|
172
|
+
const normalizeAndValidate = (changeId: string): Effect.Effect<string, ApiError> =>
|
|
173
|
+
Effect.try({
|
|
174
|
+
try: () => normalizeChangeIdentifier(changeId),
|
|
175
|
+
catch: (error) =>
|
|
176
|
+
new ApiError({
|
|
177
|
+
message: error instanceof Error ? error.message : String(error),
|
|
178
|
+
}),
|
|
179
|
+
})
|
|
180
|
+
|
|
153
181
|
const getChange = (changeId: string) =>
|
|
154
182
|
Effect.gen(function* () {
|
|
155
183
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
156
|
-
const
|
|
184
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
185
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}`
|
|
157
186
|
return yield* makeRequest(url, authHeader, 'GET', undefined, ChangeInfo)
|
|
158
187
|
})
|
|
159
188
|
|
|
@@ -169,14 +198,16 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
169
198
|
const postReview = (changeId: string, review: ReviewInput) =>
|
|
170
199
|
Effect.gen(function* () {
|
|
171
200
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
172
|
-
const
|
|
201
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
202
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/revisions/current/review`
|
|
173
203
|
yield* makeRequest(url, authHeader, 'POST', review)
|
|
174
204
|
})
|
|
175
205
|
|
|
176
206
|
const abandonChange = (changeId: string, message?: string) =>
|
|
177
207
|
Effect.gen(function* () {
|
|
178
208
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
179
|
-
const
|
|
209
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
210
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/abandon`
|
|
180
211
|
const body = message ? { message } : {}
|
|
181
212
|
yield* makeRequest(url, authHeader, 'POST', body)
|
|
182
213
|
})
|
|
@@ -199,14 +230,16 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
199
230
|
const getRevision = (changeId: string, revisionId = 'current') =>
|
|
200
231
|
Effect.gen(function* () {
|
|
201
232
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
202
|
-
const
|
|
233
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
234
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/revisions/${revisionId}`
|
|
203
235
|
return yield* makeRequest(url, authHeader, 'GET', undefined, RevisionInfo)
|
|
204
236
|
})
|
|
205
237
|
|
|
206
238
|
const getFiles = (changeId: string, revisionId = 'current') =>
|
|
207
239
|
Effect.gen(function* () {
|
|
208
240
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
209
|
-
const
|
|
241
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
242
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/revisions/${revisionId}/files`
|
|
210
243
|
return yield* makeRequest(
|
|
211
244
|
url,
|
|
212
245
|
authHeader,
|
|
@@ -224,7 +257,8 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
224
257
|
) =>
|
|
225
258
|
Effect.gen(function* () {
|
|
226
259
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
227
|
-
|
|
260
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
261
|
+
let url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/revisions/${revisionId}/files/${encodeURIComponent(filePath)}/diff`
|
|
228
262
|
if (base) {
|
|
229
263
|
url += `?base=${encodeURIComponent(base)}`
|
|
230
264
|
}
|
|
@@ -234,7 +268,8 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
234
268
|
const getFileContent = (changeId: string, filePath: string, revisionId = 'current') =>
|
|
235
269
|
Effect.gen(function* () {
|
|
236
270
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
237
|
-
const
|
|
271
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
272
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/revisions/${revisionId}/files/${encodeURIComponent(filePath)}/content`
|
|
238
273
|
|
|
239
274
|
const response = yield* Effect.tryPromise({
|
|
240
275
|
try: () =>
|
|
@@ -274,7 +309,8 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
274
309
|
const getPatch = (changeId: string, revisionId = 'current') =>
|
|
275
310
|
Effect.gen(function* () {
|
|
276
311
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
277
|
-
const
|
|
312
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
313
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/revisions/${revisionId}/patch`
|
|
278
314
|
|
|
279
315
|
const response = yield* Effect.tryPromise({
|
|
280
316
|
try: () =>
|
|
@@ -417,7 +453,8 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
417
453
|
const getComments = (changeId: string, revisionId = 'current') =>
|
|
418
454
|
Effect.gen(function* () {
|
|
419
455
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
420
|
-
const
|
|
456
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
457
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}/revisions/${revisionId}/comments`
|
|
421
458
|
return yield* makeRequest(
|
|
422
459
|
url,
|
|
423
460
|
authHeader,
|
|
@@ -430,7 +467,8 @@ export const GerritApiServiceLive: Layer.Layer<GerritApiService, never, ConfigSe
|
|
|
430
467
|
const getMessages = (changeId: string) =>
|
|
431
468
|
Effect.gen(function* () {
|
|
432
469
|
const { credentials, authHeader } = yield* getCredentialsAndAuth
|
|
433
|
-
const
|
|
470
|
+
const normalized = yield* normalizeAndValidate(changeId)
|
|
471
|
+
const url = `${credentials.host}/a/changes/${encodeURIComponent(normalized)}?o=MESSAGES`
|
|
434
472
|
const response = yield* makeRequest(url, authHeader, 'GET')
|
|
435
473
|
|
|
436
474
|
// Extract messages from the change response with runtime validation
|