@aaronshaf/ger 1.2.10 → 2.0.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/.ast-grep/rules/no-as-casting.yml +13 -0
- package/.claude-plugin/plugin.json +22 -0
- package/.github/workflows/ci-simple.yml +53 -0
- package/.github/workflows/ci.yml +171 -0
- package/.github/workflows/claude-code-review.yml +83 -0
- package/.github/workflows/claude.yml +50 -0
- package/.github/workflows/dependency-update.yml +84 -0
- package/.github/workflows/release.yml +166 -0
- package/.github/workflows/security-scan.yml +113 -0
- package/.github/workflows/security.yml +96 -0
- package/.husky/pre-commit +16 -0
- package/.husky/pre-push +25 -0
- package/.lintstagedrc.json +6 -0
- package/.tool-versions +1 -0
- package/CLAUDE.md +105 -0
- package/DEVELOPMENT.md +361 -0
- package/EXAMPLES.md +457 -0
- package/README.md +831 -16
- package/bin/ger +3 -18
- package/biome.json +36 -0
- package/bun.lock +678 -0
- package/bunfig.toml +8 -0
- package/docs/adr/0001-use-effect-for-side-effects.md +65 -0
- package/docs/adr/0002-use-bun-runtime.md +64 -0
- package/docs/adr/0003-store-credentials-in-home-directory.md +75 -0
- package/docs/adr/0004-use-commander-for-cli.md +76 -0
- package/docs/adr/0005-use-effect-schema-for-validation.md +93 -0
- package/docs/adr/0006-use-msw-for-api-mocking.md +89 -0
- package/docs/adr/0007-git-hooks-for-quality.md +94 -0
- package/docs/adr/0008-no-as-typecasting.md +83 -0
- package/docs/adr/0009-file-size-limits.md +82 -0
- package/docs/adr/0010-llm-friendly-xml-output.md +93 -0
- package/docs/adr/0011-ai-tool-strategy-pattern.md +102 -0
- package/docs/adr/0012-build-status-message-parsing.md +94 -0
- package/docs/adr/0013-git-subprocess-integration.md +98 -0
- package/docs/adr/0014-group-management-support.md +95 -0
- package/docs/adr/0015-batch-comment-processing.md +111 -0
- package/docs/adr/0016-flexible-change-identifiers.md +94 -0
- package/docs/adr/0017-git-worktree-support.md +102 -0
- package/docs/adr/0018-auto-install-commit-hook.md +103 -0
- package/docs/adr/0019-sdk-package-exports.md +95 -0
- package/docs/adr/0020-code-coverage-enforcement.md +105 -0
- package/docs/adr/0021-typescript-isolated-declarations.md +83 -0
- package/docs/adr/0022-biome-oxlint-tooling.md +124 -0
- package/docs/adr/README.md +30 -0
- package/docs/prd/README.md +12 -0
- package/docs/prd/architecture.md +325 -0
- package/docs/prd/commands.md +425 -0
- package/docs/prd/data-model.md +349 -0
- package/docs/prd/overview.md +124 -0
- package/index.ts +219 -0
- package/oxlint.json +24 -0
- package/package.json +82 -15
- package/scripts/check-coverage.ts +69 -0
- package/scripts/check-file-size.ts +38 -0
- package/scripts/fix-test-mocks.ts +55 -0
- package/skills/gerrit-workflow/SKILL.md +247 -0
- package/skills/gerrit-workflow/examples.md +572 -0
- package/skills/gerrit-workflow/reference.md +728 -0
- package/src/api/gerrit.ts +696 -0
- package/src/cli/commands/abandon.ts +65 -0
- package/src/cli/commands/add-reviewer.ts +156 -0
- package/src/cli/commands/build-status.ts +282 -0
- package/src/cli/commands/checkout.ts +422 -0
- package/src/cli/commands/comment.ts +460 -0
- package/src/cli/commands/comments.ts +85 -0
- package/src/cli/commands/diff.ts +71 -0
- package/src/cli/commands/extract-url.ts +266 -0
- package/src/cli/commands/groups-members.ts +104 -0
- package/src/cli/commands/groups-show.ts +169 -0
- package/src/cli/commands/groups.ts +137 -0
- package/src/cli/commands/incoming.ts +226 -0
- package/src/cli/commands/init.ts +164 -0
- package/src/cli/commands/mine.ts +115 -0
- package/src/cli/commands/open.ts +57 -0
- package/src/cli/commands/projects.ts +68 -0
- package/src/cli/commands/push.ts +430 -0
- package/src/cli/commands/rebase.ts +52 -0
- package/src/cli/commands/remove-reviewer.ts +123 -0
- package/src/cli/commands/restore.ts +50 -0
- package/src/cli/commands/review.ts +486 -0
- package/src/cli/commands/search.ts +162 -0
- package/src/cli/commands/setup.ts +286 -0
- package/src/cli/commands/show.ts +491 -0
- package/src/cli/commands/status.ts +35 -0
- package/src/cli/commands/submit.ts +108 -0
- package/src/cli/commands/vote.ts +119 -0
- package/src/cli/commands/workspace.ts +200 -0
- package/src/cli/index.ts +53 -0
- package/src/cli/register-commands.ts +659 -0
- package/src/cli/register-group-commands.ts +88 -0
- package/src/cli/register-reviewer-commands.ts +97 -0
- package/src/prompts/default-review.md +86 -0
- package/src/prompts/system-inline-review.md +135 -0
- package/src/prompts/system-overall-review.md +206 -0
- package/src/schemas/config.test.ts +245 -0
- package/src/schemas/config.ts +84 -0
- package/src/schemas/gerrit.ts +681 -0
- package/src/services/commit-hook.ts +314 -0
- package/src/services/config.test.ts +150 -0
- package/src/services/config.ts +250 -0
- package/src/services/git-worktree.ts +342 -0
- package/src/services/review-strategy.ts +292 -0
- package/src/test-utils/mock-generator.ts +138 -0
- package/src/utils/change-id.test.ts +98 -0
- package/src/utils/change-id.ts +63 -0
- package/src/utils/comment-formatters.ts +153 -0
- package/src/utils/diff-context.ts +103 -0
- package/src/utils/diff-formatters.ts +141 -0
- package/src/utils/formatters.ts +85 -0
- package/src/utils/git-commit.test.ts +277 -0
- package/src/utils/git-commit.ts +122 -0
- package/src/utils/index.ts +55 -0
- package/src/utils/message-filters.ts +26 -0
- package/src/utils/review-formatters.ts +89 -0
- package/src/utils/review-prompt-builder.ts +110 -0
- package/src/utils/shell-safety.ts +117 -0
- package/src/utils/status-indicators.ts +100 -0
- package/src/utils/url-parser.test.ts +271 -0
- package/src/utils/url-parser.ts +118 -0
- package/tests/abandon.test.ts +230 -0
- package/tests/add-reviewer.test.ts +579 -0
- package/tests/build-status-watch.test.ts +344 -0
- package/tests/build-status.test.ts +789 -0
- package/tests/change-id-formats.test.ts +268 -0
- package/tests/checkout/integration.test.ts +653 -0
- package/tests/checkout/parse-input.test.ts +55 -0
- package/tests/checkout/validation.test.ts +178 -0
- package/tests/comment-batch-advanced.test.ts +431 -0
- package/tests/comment-gerrit-api-compliance.test.ts +414 -0
- package/tests/comment.test.ts +708 -0
- package/tests/comments.test.ts +323 -0
- package/tests/config-service-simple.test.ts +100 -0
- package/tests/diff.test.ts +419 -0
- package/tests/extract-url.test.ts +517 -0
- package/tests/groups-members.test.ts +256 -0
- package/tests/groups-show.test.ts +323 -0
- package/tests/groups.test.ts +334 -0
- package/tests/helpers/build-status-test-setup.ts +83 -0
- package/tests/helpers/config-mock.ts +27 -0
- package/tests/incoming.test.ts +357 -0
- package/tests/init.test.ts +70 -0
- package/tests/integration/commit-hook.test.ts +246 -0
- package/tests/interactive-incoming.test.ts +173 -0
- package/tests/mine.test.ts +285 -0
- package/tests/mocks/msw-handlers.ts +80 -0
- package/tests/open.test.ts +233 -0
- package/tests/projects.test.ts +259 -0
- package/tests/rebase.test.ts +271 -0
- package/tests/remove-reviewer.test.ts +357 -0
- package/tests/restore.test.ts +237 -0
- package/tests/review.test.ts +135 -0
- package/tests/search.test.ts +712 -0
- package/tests/setup.test.ts +63 -0
- package/tests/show-auto-detect.test.ts +324 -0
- package/tests/show.test.ts +813 -0
- package/tests/status.test.ts +145 -0
- package/tests/submit.test.ts +316 -0
- package/tests/unit/commands/push.test.ts +194 -0
- package/tests/unit/git-branch-detection.test.ts +82 -0
- package/tests/unit/git-worktree.test.ts +55 -0
- package/tests/unit/patterns/push-patterns.test.ts +148 -0
- package/tests/unit/schemas/gerrit.test.ts +85 -0
- package/tests/unit/services/commit-hook.test.ts +132 -0
- package/tests/unit/services/review-strategy.test.ts +349 -0
- package/tests/unit/test-utils/mock-generator.test.ts +154 -0
- package/tests/unit/utils/comment-formatters.test.ts +415 -0
- package/tests/unit/utils/diff-context.test.ts +171 -0
- package/tests/unit/utils/diff-formatters.test.ts +165 -0
- package/tests/unit/utils/formatters.test.ts +411 -0
- package/tests/unit/utils/message-filters.test.ts +227 -0
- package/tests/unit/utils/shell-safety.test.ts +230 -0
- package/tests/unit/utils/status-indicators.test.ts +137 -0
- package/tests/vote.test.ts +317 -0
- package/tests/workspace.test.ts +295 -0
- package/tsconfig.json +36 -5
- package/src/commands/branch.ts +0 -180
- package/src/ger.ts +0 -22
- package/src/types.d.ts +0 -35
- package/src/utils.ts +0 -130
package/EXAMPLES.md
ADDED
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
# Programmatic Usage Examples
|
|
2
|
+
|
|
3
|
+
This package can be used both as a CLI tool and as a library. Below are examples of using `@aaronshaf/ger` programmatically with Effect-TS.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @aaronshaf/ger
|
|
9
|
+
# or
|
|
10
|
+
npm install @aaronshaf/ger
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Basic Setup
|
|
14
|
+
|
|
15
|
+
All services in this package are built with Effect-TS, providing type-safe, composable operations.
|
|
16
|
+
|
|
17
|
+
### Import the services
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Effect, pipe } from 'effect'
|
|
21
|
+
import {
|
|
22
|
+
GerritApiService,
|
|
23
|
+
GerritApiServiceLive,
|
|
24
|
+
ConfigServiceLive,
|
|
25
|
+
type ChangeInfo,
|
|
26
|
+
} from '@aaronshaf/ger'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
### Using Environment Variables
|
|
32
|
+
|
|
33
|
+
Set these environment variables before running your program:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export GERRIT_HOST="https://gerrit.example.com"
|
|
37
|
+
export GERRIT_USERNAME="your-username"
|
|
38
|
+
export GERRIT_PASSWORD="your-http-password"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Using File-Based Config
|
|
42
|
+
|
|
43
|
+
Or run the CLI once to set up configuration:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
ger setup
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This stores credentials in `~/.ger/config.json`.
|
|
50
|
+
|
|
51
|
+
## Examples
|
|
52
|
+
|
|
53
|
+
### 1. Get Change Information
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { Effect, pipe } from 'effect'
|
|
57
|
+
import {
|
|
58
|
+
GerritApiService,
|
|
59
|
+
GerritApiServiceLive,
|
|
60
|
+
ConfigServiceLive,
|
|
61
|
+
} from '@aaronshaf/ger'
|
|
62
|
+
|
|
63
|
+
const getChangeDetails = (changeId: string) =>
|
|
64
|
+
Effect.gen(function* () {
|
|
65
|
+
const api = yield* GerritApiService
|
|
66
|
+
const change = yield* api.getChange(changeId)
|
|
67
|
+
|
|
68
|
+
console.log(`Change: ${change.subject}`)
|
|
69
|
+
console.log(`Status: ${change.status}`)
|
|
70
|
+
console.log(`Owner: ${change.owner?.name || 'Unknown'}`)
|
|
71
|
+
|
|
72
|
+
return change
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
// Run the program
|
|
76
|
+
const program = pipe(
|
|
77
|
+
getChangeDetails('12345'),
|
|
78
|
+
Effect.provide(GerritApiServiceLive),
|
|
79
|
+
Effect.provide(ConfigServiceLive)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
Effect.runPromise(program)
|
|
83
|
+
.then(() => console.log('Done!'))
|
|
84
|
+
.catch(console.error)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. List Open Changes
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { Effect, pipe } from 'effect'
|
|
91
|
+
import {
|
|
92
|
+
GerritApiService,
|
|
93
|
+
GerritApiServiceLive,
|
|
94
|
+
ConfigServiceLive,
|
|
95
|
+
} from '@aaronshaf/ger'
|
|
96
|
+
|
|
97
|
+
const listMyChanges = Effect.gen(function* () {
|
|
98
|
+
const api = yield* GerritApiService
|
|
99
|
+
|
|
100
|
+
// Query for your open changes
|
|
101
|
+
const changes = yield* api.listChanges('is:open owner:self')
|
|
102
|
+
|
|
103
|
+
console.log(`You have ${changes.length} open changes:`)
|
|
104
|
+
for (const change of changes) {
|
|
105
|
+
console.log(` - #${change._number}: ${change.subject}`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return changes
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const program = pipe(
|
|
112
|
+
listMyChanges,
|
|
113
|
+
Effect.provide(GerritApiServiceLive),
|
|
114
|
+
Effect.provide(ConfigServiceLive)
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
Effect.runPromise(program).catch(console.error)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 2b. Search Changes with Query Syntax
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { Effect, pipe } from 'effect'
|
|
124
|
+
import {
|
|
125
|
+
GerritApiService,
|
|
126
|
+
GerritApiServiceLive,
|
|
127
|
+
ConfigServiceLive,
|
|
128
|
+
} from '@aaronshaf/ger'
|
|
129
|
+
|
|
130
|
+
const searchChanges = (query: string, limit = 25) =>
|
|
131
|
+
Effect.gen(function* () {
|
|
132
|
+
const api = yield* GerritApiService
|
|
133
|
+
|
|
134
|
+
// Use Gerrit query syntax to search changes
|
|
135
|
+
const fullQuery = query.includes('limit:') ? query : `${query} limit:${limit}`
|
|
136
|
+
const changes = yield* api.listChanges(fullQuery)
|
|
137
|
+
|
|
138
|
+
// Group by project for organized output
|
|
139
|
+
const byProject = new Map<string, typeof changes>()
|
|
140
|
+
for (const change of changes) {
|
|
141
|
+
const existing = byProject.get(change.project) ?? []
|
|
142
|
+
existing.push(change)
|
|
143
|
+
byProject.set(change.project, existing)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log(`Found ${changes.length} changes:`)
|
|
147
|
+
for (const [project, projectChanges] of byProject) {
|
|
148
|
+
console.log(`\n${project}:`)
|
|
149
|
+
for (const change of projectChanges) {
|
|
150
|
+
console.log(` #${change._number} - ${change.subject} (${change.status})`)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return changes
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
// Example queries
|
|
158
|
+
const program = pipe(
|
|
159
|
+
// Search for merged changes in the last week
|
|
160
|
+
searchChanges('status:merged age:7d', 10),
|
|
161
|
+
Effect.provide(GerritApiServiceLive),
|
|
162
|
+
Effect.provide(ConfigServiceLive)
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
Effect.runPromise(program).catch(console.error)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 3. Post a Comment
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { Effect, pipe } from 'effect'
|
|
172
|
+
import {
|
|
173
|
+
GerritApiService,
|
|
174
|
+
GerritApiServiceLive,
|
|
175
|
+
ConfigServiceLive,
|
|
176
|
+
type ReviewInput,
|
|
177
|
+
} from '@aaronshaf/ger'
|
|
178
|
+
|
|
179
|
+
const postComment = (changeId: string) =>
|
|
180
|
+
Effect.gen(function* () {
|
|
181
|
+
const api = yield* GerritApiService
|
|
182
|
+
|
|
183
|
+
const review: ReviewInput = {
|
|
184
|
+
message: 'Looks good to me!',
|
|
185
|
+
labels: {
|
|
186
|
+
'Code-Review': 1,
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
yield* api.postReview(changeId, review)
|
|
191
|
+
console.log('Comment posted successfully!')
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const program = pipe(
|
|
195
|
+
postComment('12345'),
|
|
196
|
+
Effect.provide(GerritApiServiceLive),
|
|
197
|
+
Effect.provide(ConfigServiceLive)
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
Effect.runPromise(program).catch(console.error)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 4. Post Inline Comments
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import { Effect, pipe } from 'effect'
|
|
207
|
+
import {
|
|
208
|
+
GerritApiService,
|
|
209
|
+
GerritApiServiceLive,
|
|
210
|
+
ConfigServiceLive,
|
|
211
|
+
type ReviewInput,
|
|
212
|
+
} from '@aaronshaf/ger'
|
|
213
|
+
|
|
214
|
+
const postInlineComments = (changeId: string) =>
|
|
215
|
+
Effect.gen(function* () {
|
|
216
|
+
const api = yield* GerritApiService
|
|
217
|
+
|
|
218
|
+
const review: ReviewInput = {
|
|
219
|
+
message: 'Review complete',
|
|
220
|
+
comments: {
|
|
221
|
+
'src/api.ts': [
|
|
222
|
+
{
|
|
223
|
+
line: 42,
|
|
224
|
+
message: 'Consider using const here for immutability',
|
|
225
|
+
unresolved: false,
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
line: 55,
|
|
229
|
+
message: 'This could cause a security issue',
|
|
230
|
+
unresolved: true,
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
'src/utils.ts': [
|
|
234
|
+
{
|
|
235
|
+
line: 10,
|
|
236
|
+
message: 'Nice refactor!',
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
yield* api.postReview(changeId, review)
|
|
243
|
+
console.log('Inline comments posted!')
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
const program = pipe(
|
|
247
|
+
postInlineComments('12345'),
|
|
248
|
+
Effect.provide(GerritApiServiceLive),
|
|
249
|
+
Effect.provide(ConfigServiceLive)
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
Effect.runPromise(program).catch(console.error)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### 5. Get Diff for a Change
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { Effect, pipe } from 'effect'
|
|
259
|
+
import {
|
|
260
|
+
GerritApiService,
|
|
261
|
+
GerritApiServiceLive,
|
|
262
|
+
ConfigServiceLive,
|
|
263
|
+
type DiffOptions,
|
|
264
|
+
} from '@aaronshaf/ger'
|
|
265
|
+
|
|
266
|
+
const getDiff = (changeId: string) =>
|
|
267
|
+
Effect.gen(function* () {
|
|
268
|
+
const api = yield* GerritApiService
|
|
269
|
+
|
|
270
|
+
// Get unified diff format (default)
|
|
271
|
+
const diff = yield* api.getDiff(changeId, { format: 'unified' })
|
|
272
|
+
console.log('Diff:', diff)
|
|
273
|
+
|
|
274
|
+
// Or get list of changed files
|
|
275
|
+
const files = yield* api.getDiff(changeId, { format: 'files' })
|
|
276
|
+
console.log('Changed files:', files)
|
|
277
|
+
|
|
278
|
+
return diff
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
const program = pipe(
|
|
282
|
+
getDiff('12345'),
|
|
283
|
+
Effect.provide(GerritApiServiceLive),
|
|
284
|
+
Effect.provide(ConfigServiceLive)
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
Effect.runPromise(program).catch(console.error)
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### 6. Test Connection
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
import { Effect, pipe } from 'effect'
|
|
294
|
+
import {
|
|
295
|
+
GerritApiService,
|
|
296
|
+
GerritApiServiceLive,
|
|
297
|
+
ConfigServiceLive,
|
|
298
|
+
} from '@aaronshaf/ger'
|
|
299
|
+
|
|
300
|
+
const testConnection = Effect.gen(function* () {
|
|
301
|
+
const api = yield* GerritApiService
|
|
302
|
+
const isConnected = yield* api.testConnection
|
|
303
|
+
|
|
304
|
+
if (isConnected) {
|
|
305
|
+
console.log('✓ Connected to Gerrit!')
|
|
306
|
+
} else {
|
|
307
|
+
console.log('✗ Connection failed')
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return isConnected
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
const program = pipe(
|
|
314
|
+
testConnection,
|
|
315
|
+
Effect.provide(GerritApiServiceLive),
|
|
316
|
+
Effect.provide(ConfigServiceLive)
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
Effect.runPromise(program).catch(console.error)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### 7. Error Handling with Effect
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
import { Effect, pipe, Console } from 'effect'
|
|
326
|
+
import {
|
|
327
|
+
GerritApiService,
|
|
328
|
+
GerritApiServiceLive,
|
|
329
|
+
ConfigServiceLive,
|
|
330
|
+
ApiError,
|
|
331
|
+
ConfigError,
|
|
332
|
+
} from '@aaronshaf/ger'
|
|
333
|
+
|
|
334
|
+
const safeGetChange = (changeId: string) =>
|
|
335
|
+
Effect.gen(function* () {
|
|
336
|
+
const api = yield* GerritApiService
|
|
337
|
+
const change = yield* api.getChange(changeId)
|
|
338
|
+
return change
|
|
339
|
+
}).pipe(
|
|
340
|
+
Effect.catchTag('ApiError', (error) =>
|
|
341
|
+
Console.error(`API Error: ${error.message}`).pipe(
|
|
342
|
+
Effect.map(() => null)
|
|
343
|
+
)
|
|
344
|
+
),
|
|
345
|
+
Effect.catchTag('ConfigError', (error) =>
|
|
346
|
+
Console.error(`Config Error: ${error.message}`).pipe(
|
|
347
|
+
Effect.map(() => null)
|
|
348
|
+
)
|
|
349
|
+
)
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
const program = pipe(
|
|
353
|
+
safeGetChange('invalid-change'),
|
|
354
|
+
Effect.provide(GerritApiServiceLive),
|
|
355
|
+
Effect.provide(ConfigServiceLive)
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
Effect.runPromise(program)
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### 8. Using Utilities
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
import {
|
|
365
|
+
normalizeChangeIdentifier,
|
|
366
|
+
extractChangeIdFromCommitMessage,
|
|
367
|
+
extractChangeNumber,
|
|
368
|
+
normalizeGerritHost,
|
|
369
|
+
} from '@aaronshaf/ger'
|
|
370
|
+
|
|
371
|
+
// Normalize change identifiers
|
|
372
|
+
const normalized = normalizeChangeIdentifier('12345')
|
|
373
|
+
// or
|
|
374
|
+
const normalizedId = normalizeChangeIdentifier('If5a3ae8cb5a107e187447802358417f311d0c4b1')
|
|
375
|
+
|
|
376
|
+
// Extract change ID from commit message
|
|
377
|
+
const commitMsg = `feat: add feature
|
|
378
|
+
|
|
379
|
+
Change-Id: If5a3ae8cb5a107e187447802358417f311d0c4b1`
|
|
380
|
+
|
|
381
|
+
const changeId = extractChangeIdFromCommitMessage(commitMsg)
|
|
382
|
+
console.log(changeId) // "If5a3ae8cb5a107e187447802358417f311d0c4b1"
|
|
383
|
+
|
|
384
|
+
// Extract change number from Gerrit URL
|
|
385
|
+
const url = 'https://gerrit.example.com/c/project/+/12345'
|
|
386
|
+
const changeNumber = extractChangeNumber(url)
|
|
387
|
+
console.log(changeNumber) // "12345"
|
|
388
|
+
|
|
389
|
+
// Normalize Gerrit host
|
|
390
|
+
const host = normalizeGerritHost('gerrit.example.com')
|
|
391
|
+
console.log(host) // "https://gerrit.example.com"
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### 9. Working with Schemas
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
import { Schema } from '@effect/schema'
|
|
398
|
+
import { Effect } from 'effect'
|
|
399
|
+
import { ChangeInfo, ReviewInput } from '@aaronshaf/ger'
|
|
400
|
+
|
|
401
|
+
// Validate and decode API responses
|
|
402
|
+
const validateChange = (data: unknown) =>
|
|
403
|
+
Schema.decodeUnknown(ChangeInfo)(data)
|
|
404
|
+
|
|
405
|
+
// Validate review input before sending
|
|
406
|
+
const validateReview = (review: unknown) =>
|
|
407
|
+
Schema.decodeUnknown(ReviewInput)(review)
|
|
408
|
+
|
|
409
|
+
// Use in an Effect program
|
|
410
|
+
const safeReview = Effect.gen(function* () {
|
|
411
|
+
const review = {
|
|
412
|
+
message: 'LGTM',
|
|
413
|
+
labels: { 'Code-Review': 2 },
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const validated = yield* validateReview(review)
|
|
417
|
+
console.log('Review is valid:', validated)
|
|
418
|
+
|
|
419
|
+
return validated
|
|
420
|
+
})
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Direct Module Access
|
|
424
|
+
|
|
425
|
+
You can also import directly from specific modules:
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
// Import from specific services
|
|
429
|
+
import { GerritApiService, GerritApiServiceLive } from '@aaronshaf/ger/api'
|
|
430
|
+
import { ConfigService, ConfigServiceLive } from '@aaronshaf/ger/services/config'
|
|
431
|
+
|
|
432
|
+
// Import from specific schemas
|
|
433
|
+
import { ChangeInfo, ReviewInput } from '@aaronshaf/ger/schemas/gerrit'
|
|
434
|
+
|
|
435
|
+
// Import utilities
|
|
436
|
+
import { normalizeChangeIdentifier, extractChangeNumber } from '@aaronshaf/ger/utils'
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
## TypeScript Configuration
|
|
440
|
+
|
|
441
|
+
Make sure your `tsconfig.json` includes:
|
|
442
|
+
|
|
443
|
+
```json
|
|
444
|
+
{
|
|
445
|
+
"compilerOptions": {
|
|
446
|
+
"moduleResolution": "bundler",
|
|
447
|
+
"allowImportingTsExtensions": true,
|
|
448
|
+
"strict": true
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## More Information
|
|
454
|
+
|
|
455
|
+
- See the [main README](./README.md) for CLI usage
|
|
456
|
+
- Check out the [Effect documentation](https://effect.website/) to learn more about Effect-TS
|
|
457
|
+
- View the type definitions in your IDE for detailed API documentation
|