Skip to content

Commit 50efdee

Browse files
authored
refactor: Add more cli business logic to operations (#19)
* refactor!: Convert project cli to use trailblazer operations * fix: Fixed the problem with project list feature
1 parent ce6a076 commit 50efdee

File tree

9 files changed

+157
-1
lines changed

9 files changed

+157
-1
lines changed

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ RuboCop::RakeTask.new
1515

1616
desc 'Run Cucumber features'
1717
task :cucumber do
18-
sh 'cucumber --format pretty'
18+
sh 'bundle exec cucumber --format pretty'
1919
end
2020

2121
task default: %i[rubocop test cucumber]

features/project_list.feature

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Feature: Project List
2+
As a user
3+
I want to list projects
4+
So that I can see what projects are available
5+
6+
Scenario: Listing my projects
7+
When I run `lc project list --mine`
8+
Then the output should match /Crying Game/
9+
10+
Scenario: Listing all projects
11+
When I run `lc project list`
12+
Then the output should match /Crying Game/

lib/linear/commands/project.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../cli/sub_commands'
4+
5+
module Rubyists
6+
module Linear
7+
module CLI
8+
# The Project module is the namespace for all project-related commands
9+
module Project
10+
include CLI::SubCommands
11+
12+
# Aliases for Project commands.
13+
ALIASES = {
14+
list: %w[ls l], # aliases for the list command
15+
project: %w[p projects] # aliases for the main project command itself
16+
}.freeze
17+
18+
DESCRIPTION = 'Manage projects'
19+
end
20+
end
21+
end
22+
end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# frozen_string_literal: true
2+
3+
require 'semantic_logger'
4+
5+
module Rubyists
6+
# Main module for Linear CLI commands
7+
module Linear
8+
M :project
9+
O 'project/list'
10+
module CLI
11+
module Project
12+
List = Class.new Dry::CLI::Command
13+
# The List class is a Dry::CLI::Command that lists projects
14+
class List
15+
include SemanticLogger::Loggable
16+
include Rubyists::Linear::CLI::CommonOptions
17+
18+
desc 'List projects'
19+
example [
20+
' # List all projects',
21+
'--mine # List only my projects'
22+
]
23+
option :mine, type: :boolean, default: false, desc: 'Only show my projects'
24+
25+
def call(**options)
26+
logger.debug 'Listing projects'
27+
result = Rubyists::Linear::Operations::Project::List.call(params: options)
28+
if result.success?
29+
display result[:projects], options
30+
else
31+
logger.error 'Failed to list projects'
32+
end
33+
end
34+
end
35+
end
36+
end
37+
end
38+
end

lib/linear/models/project.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ class Project
2222
updatedAt
2323
end
2424

25+
def self.mine
26+
User.me.teams.flat_map(&:projects)
27+
end
28+
2529
def slug
2630
File.basename(url).sub("-#{slugId}", '')
2731
end
@@ -49,6 +53,10 @@ def to_s
4953
def inspection
5054
format('name: "%<name>s" type: "%<url>s"', name:, url:)
5155
end
56+
57+
def display(_options)
58+
printf "%s\n", to_s
59+
end
5260
end
5361
end
5462
end

lib/linear/models/team.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,23 @@ class Team
1212
include SemanticLogger::Loggable
1313

1414
one_to_many :projects
15+
alias loaded_projects projects
16+
17+
def projects # rubocop:disable Metrics/MethodLength
18+
return @projects if @projects
19+
return @projects = loaded_projects if loaded_projects
20+
21+
team_id = data[:id]
22+
q = query do
23+
team(id: team_id) do
24+
projects(first: 100) do
25+
nodes { ___ Project.base_fragment }
26+
end
27+
end
28+
end
29+
data = Api.query(q)
30+
@projects = data.dig(:team, :projects, :nodes)&.map { |project| Project.new project } || []
31+
end
1532

1633
# TODO: Make this configurable
1734
BaseFilter = { # rubocop:disable Naming/ConstantName
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
module Rubyists
4+
module Linear
5+
module Operations
6+
module Project
7+
# The List operation lists projects
8+
class List < Trailblazer::Operation
9+
step :fetch_projects
10+
11+
def fetch_projects(ctx, params:, **)
12+
ctx[:projects] = if params[:mine]
13+
Rubyists::Linear::Project.mine
14+
else
15+
Rubyists::Linear::Project.all
16+
end
17+
end
18+
end
19+
end
20+
end
21+
end
22+
end

linear-cli.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Gem::Specification.new do |spec|
4040
spec.add_dependency 'git'
4141
spec.add_dependency 'gqli'
4242
spec.add_dependency 'httpx'
43+
spec.add_dependency 'ostruct'
4344
spec.add_dependency 'pry-byebug'
4445
spec.add_dependency 'reline'
4546
spec.add_dependency 'semantic_logger'
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../../../test_helper'
4+
require 'linear/operations/project/list'
5+
6+
class ProjectListOperationTest < Minitest::Spec
7+
describe 'Rubyists::Linear::Operations::Project::List' do
8+
let(:projects) { [Object.new, Object.new] }
9+
10+
describe 'when mine is true' do
11+
let(:params) { { mine: true } }
12+
13+
it 'fetches my projects' do
14+
Rubyists::Linear::Project.stub :mine, projects do
15+
result = Rubyists::Linear::Operations::Project::List.call(params: params)
16+
17+
_(result.success?).must_equal true
18+
_(result[:projects]).must_equal projects
19+
end
20+
end
21+
end
22+
23+
describe 'when mine is false' do
24+
let(:params) { { mine: false } }
25+
26+
it 'fetches all projects' do
27+
Rubyists::Linear::Project.stub :all, projects do
28+
result = Rubyists::Linear::Operations::Project::List.call(params: params)
29+
30+
_(result.success?).must_equal true
31+
_(result[:projects]).must_equal projects
32+
end
33+
end
34+
end
35+
end
36+
end

0 commit comments

Comments
 (0)