Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/lib/linear_cli/cli.ex
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,10 @@ defmodule LinearCli.CLI do
long: "--no-mine",
help: "List the most recent issues, not just your own"
],
no_profile: [
long: "--no-profile",
help: "Ignore the active profile's team/project defaults"
],
full: [short: "-f", long: "--full", help: "Show full issue details"],
all: [
long: "--all",
Expand Down
8 changes: 6 additions & 2 deletions app/lib/linear_cli/cli/commands.ex
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,13 @@ defmodule LinearCli.CLI.Commands do
passed explicitly always win over the active profile.
"""
def issue_list(%{flags: flags, options: options, unknown: ids}) do
team_key = options.team || Profiles.default_team()
no_profile = Map.get(flags, :no_profile, false)
team_key = options.team || unless no_profile, do: Profiles.default_team()

with {:ok, project_id} <- resolve_project_id(options.project || Profiles.default_project()) do
project_source =
options.project || unless no_profile, do: Profiles.default_project()

with {:ok, project_id} <- resolve_project_id(project_source) do
input = %{
ids: Enum.map(ids, &IssueHelpers.expand_issue_id/1),
mine: !flags.no_mine,
Expand Down
27 changes: 27 additions & 0 deletions app/test/linear_cli/cli/issue_commands_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,33 @@ defmodule LinearCli.CLI.IssueCommandsTest do
assert Map.has_key?(filter, "canceledAt")
end

test "--no-profile bypasses active profile defaults via the full CLI dispatch path" do
test_pid = self()

Req.Test.stub(LinearCli.Api, fn conn ->
{:ok, body, conn} = Plug.Conn.read_body(conn)
decoded = Jason.decode!(body)
query = decoded["query"]

if String.contains?(query, "projects(") do
raise "--no-profile must not query projects when --project wasn't given"
end

send(test_pid, {:filter, decoded["variables"]["filter"]})
Req.Test.json(conn, issues_response([issue_map()]))
end)

output =
capture_io(fn ->
assert :ok = LinearCli.CLI.main(["issue", "list", "--no-profile"])
end)

assert output =~ "CRY-1"
assert_received {:filter, filter}
refute Map.has_key?(filter, "team")
refute Map.has_key?(filter, "project")
end

test "--status with an unknown type exits 1 (Optimus parse error)" do
test_pid = self()
halt = fn code -> send(test_pid, {:halted, code}) end
Expand Down
108 changes: 108 additions & 0 deletions app/test/linear_cli/cli/profile_defaults_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,114 @@ defmodule LinearCli.CLI.ProfileDefaultsTest do
assert filter["project"] == %{"id" => %{"eq" => "p2"}}
end

test "--no-profile bypasses the active profile's team/project defaults" do
{:ok, _} = Profiles.create("manhattan", team: "CRY", project: "Manhattan Rollout")
:ok = Profiles.activate("manhattan")

test_pid = self()

Req.Test.stub(LinearCli.Api, fn conn ->
{:ok, body, conn} = Plug.Conn.read_body(conn)
decoded = Jason.decode!(body)
query = decoded["query"]

if String.contains?(query, "projects(first: $first") do
raise "--no-profile must not query projects when --project wasn't given"
end

if String.contains?(query, "issues(filter") do
send(test_pid, {:filter, decoded["variables"]["filter"]})
Req.Test.json(conn, issues_response([issue_map()]))
else
raise "no stub matched query: #{query}"
end
end)

result = %{
flags: %{no_mine: false, unassigned: false, full: false, no_profile: true},
options: %{team: nil, project: nil, output: "text"},
unknown: []
}

output = capture_io(fn -> assert :ok = Commands.issue_list(result) end)

assert output =~ "CRY-1"
assert_received {:filter, filter}
refute Map.has_key?(filter, "team")
refute Map.has_key?(filter, "project")
end

test "--no-profile with an explicit --team still applies the explicit team" do
{:ok, _} = Profiles.create("manhattan", team: "CRY", project: "Manhattan Rollout")
:ok = Profiles.activate("manhattan")

test_pid = self()

Req.Test.stub(LinearCli.Api, fn conn ->
{:ok, body, conn} = Plug.Conn.read_body(conn)
decoded = Jason.decode!(body)
query = decoded["query"]

cond do
String.contains?(query, "issues(filter") ->
send(test_pid, {:filter, decoded["variables"]["filter"]})
Req.Test.json(conn, issues_response([issue_map()]))

true ->
raise "no stub matched query: #{query}"
end
end)

result = %{
flags: %{no_mine: false, unassigned: false, full: false, no_profile: true},
options: %{team: "ENG", project: nil, output: "text"},
unknown: []
}

capture_io(fn -> assert :ok = Commands.issue_list(result) end)

assert_received {:filter, filter}
assert filter["team"] == %{"key" => %{"eq" => "ENG"}}
refute Map.has_key?(filter, "project")
end

test "--no-profile with an explicit --project still applies the explicit project" do
{:ok, _} = Profiles.create("manhattan", team: "CRY", project: "Manhattan Rollout")
:ok = Profiles.activate("manhattan")

test_pid = self()

Req.Test.stub(LinearCli.Api, fn conn ->
{:ok, body, conn} = Plug.Conn.read_body(conn)
decoded = Jason.decode!(body)
query = decoded["query"]

cond do
String.contains?(query, "projects(first: $first") ->
Req.Test.json(conn, all_projects([project_map("p3", "Platform Cleanup")]))

String.contains?(query, "issues(filter") ->
send(test_pid, {:filter, decoded["variables"]["filter"]})
Req.Test.json(conn, issues_response([issue_map()]))

true ->
raise "no stub matched query: #{query}"
end
end)

result = %{
flags: %{no_mine: false, unassigned: false, full: false, no_profile: true},
options: %{team: nil, project: "Platform Cleanup", output: "text"},
unknown: []
}

capture_io(fn -> assert :ok = Commands.issue_list(result) end)

assert_received {:filter, filter}
refute Map.has_key?(filter, "team")
assert filter["project"] == %{"id" => %{"eq" => "p3"}}
end

test "resolves bare issue numbers (positional ids) via the active profile's team" do
{:ok, _} = Profiles.create("manhattan", team: "CRY")
:ok = Profiles.activate("manhattan")
Expand Down