Skip to content

Commit aa4657f

Browse files
bougymanclaude
andcommitted
fix(issue-list): add --no-profile flag to bypass active profile defaults
Adds a `--no-profile` boolean flag to `issue list`. When set, the `team_key` and `project_id` fields no longer fall back to `Profiles.default_team()` / `Profiles.default_project()`, so the command behaves as if no profile is active. Explicit `--team` / `--project` still take effect even when `--no-profile` is set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c61d842 commit aa4657f

4 files changed

Lines changed: 176 additions & 2 deletions

File tree

app/lib/linear_cli/cli.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,10 @@ defmodule LinearCli.CLI do
509509
long: "--no-mine",
510510
help: "List the most recent issues, not just your own"
511511
],
512+
no_profile: [
513+
long: "--no-profile",
514+
help: "Ignore the active profile's team/project defaults"
515+
],
512516
full: [short: "-f", long: "--full", help: "Show full issue details"],
513517
all: [
514518
long: "--all",

app/lib/linear_cli/cli/commands.ex

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,13 @@ defmodule LinearCli.CLI.Commands do
226226
passed explicitly always win over the active profile.
227227
"""
228228
def issue_list(%{flags: flags, options: options, unknown: ids}) do
229-
team_key = options.team || Profiles.default_team()
229+
no_profile = Map.get(flags, :no_profile, false)
230+
team_key = options.team || (unless no_profile, do: Profiles.default_team())
230231

231-
with {:ok, project_id} <- resolve_project_id(options.project || Profiles.default_project()) do
232+
project_source =
233+
options.project || (unless no_profile, do: Profiles.default_project())
234+
235+
with {:ok, project_id} <- resolve_project_id(project_source) do
232236
input = %{
233237
ids: Enum.map(ids, &IssueHelpers.expand_issue_id/1),
234238
mine: !flags.no_mine,

app/test/linear_cli/cli/issue_commands_test.exs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,33 @@ defmodule LinearCli.CLI.IssueCommandsTest do
282282
assert Map.has_key?(filter, "canceledAt")
283283
end
284284

285+
test "--no-profile bypasses active profile defaults via the full CLI dispatch path" do
286+
test_pid = self()
287+
288+
Req.Test.stub(LinearCli.Api, fn conn ->
289+
{:ok, body, conn} = Plug.Conn.read_body(conn)
290+
decoded = Jason.decode!(body)
291+
query = decoded["query"]
292+
293+
if String.contains?(query, "projects(") do
294+
raise "--no-profile must not query projects when --project wasn't given"
295+
end
296+
297+
send(test_pid, {:filter, decoded["variables"]["filter"]})
298+
Req.Test.json(conn, issues_response([issue_map()]))
299+
end)
300+
301+
output =
302+
capture_io(fn ->
303+
assert :ok = LinearCli.CLI.main(["issue", "list", "--no-profile"])
304+
end)
305+
306+
assert output =~ "CRY-1"
307+
assert_received {:filter, filter}
308+
refute Map.has_key?(filter, "team")
309+
refute Map.has_key?(filter, "project")
310+
end
311+
285312
test "--status with an unknown type exits 1 (Optimus parse error)" do
286313
test_pid = self()
287314
halt = fn code -> send(test_pid, {:halted, code}) end

app/test/linear_cli/cli/profile_defaults_test.exs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,74 @@ defmodule LinearCli.CLI.ProfileDefaultsTest do
216216
assert filter["project"] == %{"id" => %{"eq" => "p2"}}
217217
end
218218

219+
test "--no-profile bypasses the active profile's team/project defaults" do
220+
{:ok, _} = Profiles.create("manhattan", team: "CRY", project: "Manhattan Rollout")
221+
:ok = Profiles.activate("manhattan")
222+
223+
test_pid = self()
224+
225+
Req.Test.stub(LinearCli.Api, fn conn ->
226+
{:ok, body, conn} = Plug.Conn.read_body(conn)
227+
decoded = Jason.decode!(body)
228+
query = decoded["query"]
229+
230+
cond do
231+
String.contains?(query, "issues(filter") ->
232+
send(test_pid, {:filter, decoded["variables"]["filter"]})
233+
Req.Test.json(conn, issues_response([issue_map()]))
234+
235+
true ->
236+
raise "no stub matched query: #{query}"
237+
end
238+
end)
239+
240+
result = %{
241+
flags: %{no_mine: false, unassigned: false, full: false, no_profile: true},
242+
options: %{team: nil, project: nil, output: "text"},
243+
unknown: []
244+
}
245+
246+
capture_io(fn -> assert :ok = Commands.issue_list(result) end)
247+
248+
assert_received {:filter, filter}
249+
refute Map.has_key?(filter, "team")
250+
refute Map.has_key?(filter, "project")
251+
end
252+
253+
test "--no-profile with an explicit --team still applies the explicit team" do
254+
{:ok, _} = Profiles.create("manhattan", team: "CRY", project: "Manhattan Rollout")
255+
:ok = Profiles.activate("manhattan")
256+
257+
test_pid = self()
258+
259+
Req.Test.stub(LinearCli.Api, fn conn ->
260+
{:ok, body, conn} = Plug.Conn.read_body(conn)
261+
decoded = Jason.decode!(body)
262+
query = decoded["query"]
263+
264+
cond do
265+
String.contains?(query, "issues(filter") ->
266+
send(test_pid, {:filter, decoded["variables"]["filter"]})
267+
Req.Test.json(conn, issues_response([issue_map()]))
268+
269+
true ->
270+
raise "no stub matched query: #{query}"
271+
end
272+
end)
273+
274+
result = %{
275+
flags: %{no_mine: false, unassigned: false, full: false, no_profile: true},
276+
options: %{team: "ENG", project: nil, output: "text"},
277+
unknown: []
278+
}
279+
280+
capture_io(fn -> assert :ok = Commands.issue_list(result) end)
281+
282+
assert_received {:filter, filter}
283+
assert filter["team"] == %{"key" => %{"eq" => "ENG"}}
284+
refute Map.has_key?(filter, "project")
285+
end
286+
219287
test "resolves bare issue numbers (positional ids) via the active profile's team" do
220288
{:ok, _} = Profiles.create("manhattan", team: "CRY")
221289
:ok = Profiles.activate("manhattan")
@@ -250,6 +318,77 @@ defmodule LinearCli.CLI.ProfileDefaultsTest do
250318
end
251319
end
252320

321+
describe "Commands.issue_list/1 with --no-profile bypasses active profile defaults" do
322+
test "ignores both team and project defaults when --no-profile is set" do
323+
{:ok, _} = Profiles.create("manhattan", team: "CRY", project: "Manhattan Rollout")
324+
:ok = Profiles.activate("manhattan")
325+
326+
test_pid = self()
327+
328+
Req.Test.stub(LinearCli.Api, fn conn ->
329+
{:ok, body, conn} = Plug.Conn.read_body(conn)
330+
decoded = Jason.decode!(body)
331+
query = decoded["query"]
332+
333+
if String.contains?(query, "projects(first: $first") do
334+
raise "--no-profile must not query projects when --project wasn't given"
335+
end
336+
337+
if String.contains?(query, "issues(filter") do
338+
send(test_pid, {:filter, decoded["variables"]["filter"]})
339+
Req.Test.json(conn, issues_response([issue_map()]))
340+
else
341+
raise "no stub matched query: #{query}"
342+
end
343+
end)
344+
345+
result = %{
346+
flags: %{no_mine: false, unassigned: false, full: false, no_profile: true},
347+
options: %{team: nil, project: nil, output: "text"},
348+
unknown: []
349+
}
350+
351+
output = capture_io(fn -> assert :ok = Commands.issue_list(result) end)
352+
353+
assert output =~ "CRY-1"
354+
assert_received {:filter, filter}
355+
refute Map.has_key?(filter, "team")
356+
refute Map.has_key?(filter, "project")
357+
end
358+
359+
test "--no-profile with explicit --team still applies the explicit team" do
360+
{:ok, _} = Profiles.create("manhattan", team: "CRY", project: "Manhattan Rollout")
361+
:ok = Profiles.activate("manhattan")
362+
363+
test_pid = self()
364+
365+
Req.Test.stub(LinearCli.Api, fn conn ->
366+
{:ok, body, conn} = Plug.Conn.read_body(conn)
367+
decoded = Jason.decode!(body)
368+
query = decoded["query"]
369+
370+
if String.contains?(query, "issues(filter") do
371+
send(test_pid, {:filter, decoded["variables"]["filter"]})
372+
Req.Test.json(conn, issues_response([issue_map()]))
373+
else
374+
raise "no stub matched query: #{query}"
375+
end
376+
end)
377+
378+
result = %{
379+
flags: %{no_mine: false, unassigned: false, full: false, no_profile: true},
380+
options: %{team: "ENG", project: nil, output: "text"},
381+
unknown: []
382+
}
383+
384+
capture_io(fn -> assert :ok = Commands.issue_list(result) end)
385+
386+
assert_received {:filter, filter}
387+
assert filter["team"] == %{"key" => %{"eq" => "ENG"}}
388+
refute Map.has_key?(filter, "project")
389+
end
390+
end
391+
253392
describe "Commands.issue_update/1 resolves bare issue numbers via the active profile" do
254393
test "expands a bare positional id before looking it up" do
255394
{:ok, _} = Profiles.create("manhattan", team: "CRY")

0 commit comments

Comments
 (0)