diff --git a/src/commands/me.ts b/src/commands/me.ts index ad527a8..c43258a 100644 --- a/src/commands/me.ts +++ b/src/commands/me.ts @@ -1,6 +1,17 @@ import type { Command } from 'commander' import { ApiClient } from '../lib/api' import { printJson, runAction } from '../lib/output' +import type { WhoAmI } from '../lib/types' + +// Renders the human-readable identity summary. Prefers the GitHub login over the +// bare numeric user id when the server resolved a gh_user, falling back to the id. +export function renderMe(me: WhoAmI): void { + console.log(`customer: ${me.customer_login} (${me.customer_id})`) + if (me.gh_user) console.log(`user: ${me.gh_user.login} (${me.user_id})`) + else if (me.user_id) console.log(`user: ${me.user_id}`) + if (me.api_key_id) console.log(`api key: ${me.api_key_id}`) + if (me.sandbox_id) console.log(`sandbox: ${me.sandbox_id}`) +} export function registerMe(program: Command): void { program @@ -14,10 +25,7 @@ export function registerMe(program: Command): void { printJson(me) return } - console.log(`customer: ${me.customer_login} (${me.customer_id})`) - if (me.user_id) console.log(`user: ${me.user_id}`) - if (me.api_key_id) console.log(`api key: ${me.api_key_id}`) - if (me.sandbox_id) console.log(`sandbox: ${me.sandbox_id}`) + renderMe(me) }) }) } diff --git a/src/lib/types.ts b/src/lib/types.ts index 1b69d42..f24a353 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -6,10 +6,20 @@ // ------------------------------- identity ------------------------------- +// The GitHub user behind a user_id, when we have it cached. Loosely typed: the +// CLI only reads `login`; the rest of the GithubUser fields are passed through. +export interface GhUser { + id: number + login: string + name: string | null + [key: string]: unknown +} + export interface WhoAmI { customer_id: string customer_login: string user_id: string | null + gh_user: GhUser | null api_key_id: string | null sandbox_id: string | null } diff --git a/test/me.test.ts b/test/me.test.ts new file mode 100644 index 0000000..639087a --- /dev/null +++ b/test/me.test.ts @@ -0,0 +1,47 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { renderMe } from '../src/commands/me' +import type { WhoAmI } from '../src/lib/types' + +function base(overrides: Partial = {}): WhoAmI { + return { + customer_id: 'cust_1', + customer_login: 'ellipsis-dev', + user_id: null, + gh_user: null, + api_key_id: null, + sandbox_id: null, + ...overrides, + } +} + +describe('renderMe', () => { + let lines: string[] + beforeEach(() => { + lines = [] + vi.spyOn(console, 'log').mockImplementation((msg?: unknown) => { + lines.push(String(msg)) + }) + }) + afterEach(() => vi.restoreAllMocks()) + + it('shows the gh_user login alongside the id when resolved', () => { + renderMe( + base({ + user_id: '24214708', + gh_user: { id: 24214708, login: 'hbrooks', name: 'Hunter' }, + }), + ) + expect(lines).toContain('user: hbrooks (24214708)') + }) + + it('falls back to the bare user id when gh_user is null', () => { + renderMe(base({ user_id: '24214708', gh_user: null })) + expect(lines).toContain('user: 24214708') + }) + + it('omits the user line entirely for api-key principals', () => { + renderMe(base({ api_key_id: 'eak_123' })) + expect(lines.some((l) => l.startsWith('user:'))).toBe(false) + expect(lines).toContain('api key: eak_123') + }) +})