Skip to content

Commit e5c0fca

Browse files
committed
fix: error when --workspace flag specifies unknown workspace
Previously, --workspace would silently fall back to other credential sources when the specified workspace wasn't found. Now it errors with a helpful message suggesting `linear auth login` or `linear auth list`. Also errors when both LINEAR_API_KEY env var and --workspace are set, since these are conflicting ways to specify credentials. Added error handling guidelines to CLAUDE.md to prevent silent failures.
1 parent 1b4135b commit e5c0fca

File tree

3 files changed

+91
-11
lines changed

3 files changed

+91
-11
lines changed

CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
- see [docs/deno-permissions.md](docs/deno-permissions.md) for the full list of files to update when adding new permissions
1616
- key files: `deno.json` (tasks), `dist-workspace.toml` (release builds), test files
1717

18+
## error handling
19+
20+
- never fail silently - if something goes wrong or a lookup fails, throw an error with a helpful message
21+
- when user-provided input (flags, args) doesn't match expected values, error immediately with guidance on how to fix it
22+
- avoid falling back to defaults when explicit user input is invalid; explicit input should either work or error
23+
1824
## tests
1925

2026
- tests on commands should mirror the directory structure of the src, e.g.

src/utils/graphql.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,35 +38,54 @@ export function logClientError(error: ClientError): void {
3838

3939
/**
4040
* Get the resolved API key following the precedence chain:
41-
* 1. --api-key CLI flag (explicit key)
42-
* 2. LINEAR_API_KEY env var
43-
* 3. api_key in project config
44-
* 4. --workspace flag → credentials lookup
45-
* 5. Project's workspace config → credentials lookup
46-
* 6. default workspace from credentials file
41+
* 1. LINEAR_API_KEY env var (conflicts with --workspace)
42+
* 2. api_key in project config
43+
* 3. --workspace flag → credentials lookup
44+
* 4. Project's workspace config → credentials lookup
45+
* 5. default workspace from credentials file
4746
*/
4847
export function getResolvedApiKey(): string | undefined {
49-
// 1-3: Check existing sources (CLI flag, env var, project config)
48+
const cliWorkspace = getCliWorkspace()
49+
const envApiKey = Deno.env.get("LINEAR_API_KEY")
50+
51+
// Error if both LINEAR_API_KEY and --workspace are set
52+
if (envApiKey && cliWorkspace) {
53+
throw new Error(
54+
"Cannot use --workspace flag when LINEAR_API_KEY environment variable is set. " +
55+
"Either unset LINEAR_API_KEY or remove the --workspace flag.",
56+
)
57+
}
58+
59+
// 1: LINEAR_API_KEY env var
60+
if (envApiKey) {
61+
return envApiKey
62+
}
63+
64+
// 2: api_key in project config
5065
const configApiKey = getOption("api_key")
5166
if (configApiKey) {
5267
return configApiKey
5368
}
5469

55-
// 4: --workspace flag → credentials lookup
56-
const cliWorkspace = getCliWorkspace()
70+
// 3: --workspace flag → credentials lookup
5771
if (cliWorkspace) {
5872
const key = getCredentialApiKey(cliWorkspace)
5973
if (key) return key
74+
// Explicit --workspace flag must match a configured workspace
75+
throw new Error(
76+
`Workspace "${cliWorkspace}" not found in credentials. ` +
77+
`Run \`linear auth login\` to add it, or \`linear auth list\` to see configured workspaces.`,
78+
)
6079
}
6180

62-
// 5: Project's workspace config → credentials lookup
81+
// 4: Project's workspace config → credentials lookup
6382
const projectWorkspace = getOption("workspace")
6483
if (projectWorkspace) {
6584
const key = getCredentialApiKey(projectWorkspace)
6685
if (key) return key
6786
}
6887

69-
// 6: Default workspace from credentials file
88+
// 5: Default workspace from credentials file
7089
return getCredentialApiKey()
7190
}
7291

test/utils/graphql.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { assertEquals, assertStringIncludes, assertThrows } from "@std/assert"
2+
import { setCliWorkspace } from "../../src/config.ts"
3+
import { getResolvedApiKey } from "../../src/utils/graphql.ts"
4+
5+
Deno.test("getResolvedApiKey - errors when --workspace not found in credentials", () => {
6+
// Setup - use a workspace name that definitely doesn't exist
7+
Deno.env.delete("LINEAR_API_KEY")
8+
setCliWorkspace("nonexistent-workspace-xyz-123")
9+
10+
try {
11+
const error = assertThrows(
12+
() => getResolvedApiKey(),
13+
Error,
14+
)
15+
assertStringIncludes(
16+
error.message,
17+
'Workspace "nonexistent-workspace-xyz-123" not found in credentials',
18+
)
19+
} finally {
20+
// Cleanup
21+
setCliWorkspace(undefined)
22+
}
23+
})
24+
25+
Deno.test("getResolvedApiKey - errors when LINEAR_API_KEY and --workspace both set", () => {
26+
// Setup
27+
Deno.env.set("LINEAR_API_KEY", "test-api-key")
28+
setCliWorkspace("test-workspace")
29+
30+
try {
31+
assertThrows(
32+
() => getResolvedApiKey(),
33+
Error,
34+
"Cannot use --workspace flag when LINEAR_API_KEY environment variable is set",
35+
)
36+
} finally {
37+
// Cleanup
38+
Deno.env.delete("LINEAR_API_KEY")
39+
setCliWorkspace(undefined)
40+
}
41+
})
42+
43+
Deno.test("getResolvedApiKey - returns LINEAR_API_KEY when set without --workspace", () => {
44+
// Setup
45+
Deno.env.set("LINEAR_API_KEY", "test-api-key")
46+
setCliWorkspace(undefined)
47+
48+
try {
49+
const result = getResolvedApiKey()
50+
assertEquals(result, "test-api-key")
51+
} finally {
52+
// Cleanup
53+
Deno.env.delete("LINEAR_API_KEY")
54+
}
55+
})

0 commit comments

Comments
 (0)