feat(@helm/adapters): scaffold IssueTrackerAdapter interface and MockAdapter#7
Conversation
… interface + types New pure-TypeScript package with zero runtime deps of its own. IssueTrackerAdapter interface (interface.ts): ensureSubStages(config: IssueTracker) — idempotent setup getItem / listItems — reads, returns null on missing setSubStage / setStatus / comment — writes parseWebhook (sync) — normalises raw webhook payloads registerWebhook — registers Helm's callback URL NormalizedItem: externalId, title, subStage (WorkflowStage|null), status, url. No EXTERNAL_ID_REGEX here — FS validation stays at ItemStore boundary. NormalizedEvent discriminated union: item_created | item_updated (new values, not diff) | comment_added | unknown (safe catch-all). ItemFilter: optional status and subStage predicates for listItems(). WorkflowStage imported directly from @helm/workflow (not via @helm/shared re-export) per convention for new packages. IssueTracker imported from @helm/shared. @types/node added as devDep (tsc traverses shared source). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements all 8 IssueTrackerAdapter methods in memory (Map-backed), adds seed/getComments test helpers, and covers 19 contract scenarios with Vitest. Updates index.ts to export MockAdapter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds the ChangesAdapters Framework Package
sequenceDiagram
participant Developer
participant MockAdapter
participant Internal as Internal_Maps
participant TestSuite
Developer->>MockAdapter: seed(item)
MockAdapter->>Internal: store NormalizedItem
TestSuite->>MockAdapter: getItem(externalId)
MockAdapter->>Internal: lookup Map
MockAdapter-->>TestSuite: NormalizedItem or null
TestSuite->>MockAdapter: listItems(filter?)
MockAdapter->>Internal: filter by status/subStage
MockAdapter-->>TestSuite: NormalizedItem[]
TestSuite->>MockAdapter: setSubStage(externalId, stage)
MockAdapter->>Internal: validate & update
MockAdapter-->>TestSuite: resolve or throw
TestSuite->>MockAdapter: parseWebhook(rawEvent)
MockAdapter->>MockAdapter: shape check
MockAdapter-->>TestSuite: NormalizedEvent
🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs:
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/adapters/src/mock-adapter.ts`:
- Around line 22-33: getItem and listItems return direct references from
this.items, allowing callers to mutate adapter state; change both to return
defensive copies instead. In getItem (function getItem) return a clone of the
found NormalizedItem (or null) instead of the stored object; in listItems
(function listItems) return an array of clones (apply the same filtering logic
but map to clones before returning). Use a safe cloning approach (e.g.,
structuredClone or an equivalent deep-clone utility) so external callers cannot
modify the internal this.items state and must use setSubStage/setStatus to
change items.
- Around line 60-69: The shape guard in parseWebhook is too permissive: ensure
the rawEvent.type is a string before casting to NormalizedEvent. Update
parseWebhook to check that rawEvent is an object, has a 'type' property, and
that (rawEvent as { type: unknown }).type is typeof 'string' and not equal to
'unknown' (e.g., add typeof (rawEvent as { type: unknown }).type === 'string' &&
(rawEvent as { type: string }).type !== 'unknown'); only then return rawEvent as
NormalizedEvent, otherwise return the fallback { type: 'unknown', raw: rawEvent
}.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 523ac6b4-6274-4b93-ad7f-63e5a9f3c2e8
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
packages/adapters/package.jsonpackages/adapters/src/index.tspackages/adapters/src/interface.tspackages/adapters/src/mock-adapter.test.tspackages/adapters/src/mock-adapter.tspackages/adapters/src/types.tspackages/adapters/tsconfig.json
…type guard - getItem/listItems now return shallow copies to prevent external mutation of internal Map state - parseWebhook now checks typeof type === 'string' before pass-through, rejecting numeric/non-string type values as unknown events - Added test covering numeric type value edge case Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/adapters/src/mock-adapter.ts`:
- Around line 63-70: The parseWebhook implementation can still throw when
accessing properties on hostile objects; update the parseWebhook function to
wrap the existing detection/destructuring logic in a try-catch so any thrown
error is swallowed and the function always returns a NormalizedEvent; on error
(or when checks fail) return { type: 'unknown', raw: rawEvent } as the fallback
per the adapter contract, keeping NormalizedEvent and parseWebhook identifiers
unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1220b972-4458-4c4f-be87-738ca00f2c1c
📒 Files selected for processing (2)
packages/adapters/src/mock-adapter.test.tspackages/adapters/src/mock-adapter.ts
…throw contract
The interface requires parseWebhook to never throw. Property access on Proxy
objects (or objects with throwing getters) can still raise even after the
typeof check. Wrap in try-catch and fall back to {type:'unknown'} on any error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@CodeRabbit are we clean? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chainLet me take a thorough look at the code before giving you a verdict. 🏁 Script executed: Length of output: 14342 Let me quickly verify the 🏁 Script executed: Length of output: 3220
🟡 Minor observations1. "devDependencies": {
"@types/node": "^22.19.19",
"vitest": "^2.1.9"
}2. ensureSubStages(config: IssueTracker): Promise<void>;
registerWebhook(callbackUrl: string): Promise<void>;…but 3. Everything else — the type design, the defensive |
vitest was relying on pnpm root-level hoisting; declare it explicitly so the package is self-contained if shamefully-hoist is ever disabled. @types/node has no callers in src/ and can be removed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
@helm/adapterspackage withIssueTrackerAdapterTypeScript interface, shared types (NormalizedItem,NormalizedEvent,ItemFilter), and an in-memoryMockAdapterfor use in testsMockAdapterprovidesseed()/getComments()helpers and implements all 8 interface methods;setSubStage,setStatus, andcommentthrow if the item doesn't existparseWebhookpass-through / unknown fallbackTest plan
pnpm --filter @helm/adapters test— all 19 tests passpnpm --filter @helm/adapters build—tsc --noEmitclean🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Tests
Chores