3llo 1.0.0.pre.rc.0 → 1.3.1.pre.rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +4 -0
  3. data/.rubocop.yml +122 -0
  4. data/3llo.gemspec +11 -11
  5. data/CHANGELOG.md +21 -0
  6. data/Gemfile +3 -3
  7. data/LICENSE +2 -1
  8. data/Rakefile +3 -9
  9. data/bin/3llo +4 -4
  10. data/lib/3llo/api/board.rb +23 -27
  11. data/lib/3llo/api/card.rb +87 -103
  12. data/lib/3llo/api/checklist.rb +26 -48
  13. data/lib/3llo/api/label.rb +64 -0
  14. data/lib/3llo/api/list.rb +22 -23
  15. data/lib/3llo/api/token.rb +2 -2
  16. data/lib/3llo/api/user.rb +8 -32
  17. data/lib/3llo/api.rb +7 -6
  18. data/lib/3llo/application.rb +32 -22
  19. data/lib/3llo/command/board/add.rb +29 -0
  20. data/lib/3llo/command/board.rb +7 -9
  21. data/lib/3llo/command/card/add.rb +12 -8
  22. data/lib/3llo/command/card/add_label.rb +56 -0
  23. data/lib/3llo/command/card/assign.rb +3 -3
  24. data/lib/3llo/command/card/edit.rb +33 -0
  25. data/lib/3llo/command/card/move.rb +3 -7
  26. data/lib/3llo/command/card/self_assign.rb +2 -2
  27. data/lib/3llo/command/card.rb +42 -53
  28. data/lib/3llo/command/label/add.rb +22 -0
  29. data/lib/3llo/command/label/edit.rb +37 -0
  30. data/lib/3llo/command/label/invalid.rb +18 -0
  31. data/lib/3llo/command/label/list.rb +18 -0
  32. data/lib/3llo/command/label/remove.rb +28 -0
  33. data/lib/3llo/command/label.rb +47 -0
  34. data/lib/3llo/command/list/add.rb +21 -0
  35. data/lib/3llo/command/list.rb +10 -9
  36. data/lib/3llo/command.rb +47 -14
  37. data/lib/3llo/controller.rb +28 -13
  38. data/lib/3llo/entities.rb +2 -2
  39. data/lib/3llo/interface.rb +3 -2
  40. data/lib/3llo/registry.rb +3 -4
  41. data/lib/3llo/remote_server.rb +99 -0
  42. data/lib/3llo/utils.rb +18 -0
  43. data/lib/3llo/version.rb +1 -1
  44. data/lib/3llo/view/board/help.rb +1 -0
  45. data/lib/3llo/view/board/list.rb +2 -2
  46. data/lib/3llo/view/card/help.rb +2 -1
  47. data/lib/3llo/view/help.rb +2 -0
  48. data/lib/3llo/view/label/help.rb +20 -0
  49. data/lib/3llo/view/label/list.rb +21 -0
  50. data/lib/3llo/view/list/help.rb +1 -0
  51. data/lib/3llo/view.rb +13 -11
  52. data/lib/3llo.rb +14 -14
  53. metadata +38 -9
  54. data/lib/3llo/http/client.rb +0 -95
  55. data/lib/3llo/http/request_error.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c80cabc5ec119676b74fbcc4bc8690d1a2bf55b2f53358f8069e788e36e4049
4
- data.tar.gz: a1690b3ce4cbdb9ded4421f168037f458064769c802def01d21faf1e7f0bbab1
3
+ metadata.gz: df1f778545dbad0dd5c3e98af6827fbb9a8d5b28ed12ae52d6a0128fd23eae24
4
+ data.tar.gz: 4a80160dc866ff204f5e0d5cc205a7c3a7759634104483c7fd51bacb636c9b8e
5
5
  SHA512:
6
- metadata.gz: e4aae96a782fda12b5f87ada27e76a173e04f6dc707f46a45779e2b3c9440833c90e9ab099e35717ad49d55132664f94207f1e9b26c68df1371c7dafd539a70b
7
- data.tar.gz: 1d0a9482ace979945ff7f8f25ec6b92cb07e8d1733c9b9a97624aeeeaa319ad29e73eda694c5618a1ef2efe665d51d1be4923e20efea98f03e724d355b403ce9
6
+ metadata.gz: 7779e29c81f5b63700b264f15cc8c3b8ef76289b34d1b94dca213bf2a01d40537e1a8d61f3c5bee434747feba98fb78e8a4d1fd1a59d16d980b41d2ddd08788e
7
+ data.tar.gz: 3f08a5fda5d1ed16e3c2c0e2e177d5bd4e8d911f88fd93338c1477ba2e80d299f8b16b9be350c487648a876b1da9a2ab0e7e21d98c56d85eb4f03c9a85c0ebd0
@@ -25,5 +25,9 @@ jobs:
25
25
  run: |
26
26
  gem install bundler
27
27
  bundle install --jobs 4 --retry 3
28
+ - name: Start httpbin container
29
+ run: docker run -d -p 8080:80 kennethreitz/httpbin
30
+ - name: Run Rubocop
31
+ run: bundle exec rubocop
28
32
  - name: Run test
29
33
  run: bundle exec rspec
data/.rubocop.yml ADDED
@@ -0,0 +1,122 @@
1
+ # The behavior of RuboCop can be controlled via the .rubocop.yml
2
+ # configuration file. It makes it possible to enable/disable
3
+ # certain cops (checks) and to alter their behavior if they accept
4
+ # any parameters. The file can be placed either in your home
5
+ # directory or in some project directory.
6
+ #
7
+ # RuboCop will start looking for the configuration file in the directory
8
+ # where the inspected file is and continue its way up to the root directory.
9
+ #
10
+ # See https://github.com/rubocop-hq/rubocop/blob/master/manual/configuration.md
11
+
12
+ AllCops:
13
+ TargetRubyVersion: 2.5
14
+
15
+ Layout/LineLength:
16
+ Max: 120
17
+
18
+ Layout/DotPosition:
19
+ EnforcedStyle: leading
20
+
21
+ Layout/EmptyLinesAroundBlockBody:
22
+ EnforcedStyle: no_empty_lines
23
+
24
+ Layout/FirstArrayElementIndentation:
25
+ EnforcedStyle: consistent
26
+
27
+ Layout/FirstHashElementIndentation:
28
+ EnforcedStyle: consistent
29
+
30
+ Layout/HeredocIndentation:
31
+ Enabled: false
32
+
33
+ Layout/MultilineMethodCallIndentation:
34
+ EnforcedStyle: indented
35
+
36
+ Layout/SpaceInsideBlockBraces:
37
+ EnforcedStyle: space
38
+
39
+ Layout/SpaceInsideHashLiteralBraces:
40
+ EnforcedStyle: no_space
41
+
42
+ Layout/SpaceInsideParens:
43
+ EnforcedStyle: no_space
44
+
45
+ Lint/AssignmentInCondition:
46
+ Enabled: false
47
+
48
+ Metrics:
49
+ Enabled: false
50
+
51
+ Naming/RescuedExceptionsVariableName:
52
+ Enabled: false
53
+
54
+ Security/JSONLoad:
55
+ Enabled: false
56
+
57
+ Style/Alias:
58
+ EnforcedStyle: prefer_alias
59
+
60
+ Style/HashEachMethods:
61
+ Enabled: true
62
+
63
+ Style/HashTransformKeys:
64
+ Enabled: true
65
+
66
+ Style/HashTransformValues:
67
+ Enabled: true
68
+
69
+ Style/DefWithParentheses:
70
+ Enabled: false
71
+
72
+ Style/Documentation:
73
+ Enabled: false
74
+
75
+ Style/FrozenStringLiteralComment:
76
+ Enabled: false
77
+
78
+ Style/GlobalVars:
79
+ AllowedVariables: ['$application']
80
+
81
+ Style/GuardClause:
82
+ Enabled: false
83
+
84
+ Style/HashSyntax:
85
+ EnforcedStyle: ruby19
86
+
87
+ Style/MethodCallWithoutArgsParentheses:
88
+ Enabled: false
89
+
90
+ Style/ModuleFunction:
91
+ Enabled: false
92
+
93
+ Style/MultilineBlockChain:
94
+ Enabled: false
95
+
96
+ Style/PreferredHashMethods:
97
+ EnforcedStyle: verbose
98
+
99
+ Style/TrailingCommaInArguments:
100
+ EnforcedStyleForMultiline: no_comma
101
+
102
+ Style/TrailingCommaInHashLiteral:
103
+ EnforcedStyleForMultiline: no_comma
104
+
105
+ Style/WordArray:
106
+ EnforcedStyle: percent
107
+ MinSize: 3
108
+
109
+ Style/SpecialGlobalVars:
110
+ EnforcedStyle: use_english_names
111
+
112
+ Style/StringLiterals:
113
+ EnforcedStyle: double_quotes
114
+
115
+ Style/StringLiteralsInInterpolation:
116
+ EnforcedStyle: double_quotes
117
+
118
+ Style/RaiseArgs:
119
+ EnforcedStyle: compact
120
+
121
+ Lint/NonDeterministicRequireOrder:
122
+ Enabled: false
data/3llo.gemspec CHANGED
@@ -1,21 +1,20 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path("lib", __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require '3llo/version'
3
+ require "3llo/version"
5
4
 
6
5
  Gem::Specification.new do |spec|
7
6
  spec.name = "3llo"
8
7
  spec.version = Tr3llo::VERSION
9
- spec.authors = ["Cẩm Huỳnh"]
10
- spec.email = ["huynhquancam@gmail.com"]
8
+ spec.authors = ["Cẩm Huỳnh", "Diệp Sở Hùng"]
9
+ spec.email = ["huynhquancam@gmail.com", "diepsohung@gmail.com"]
11
10
 
12
- spec.summary = %q{Trello CLI app}
13
- spec.description = %q{Interactive CLI application for Trello}
11
+ spec.summary = "Trello CLI app"
12
+ spec.description = "Interactive CLI application for Trello"
14
13
  spec.homepage = "https://github.com/qcam/3llo"
15
14
  spec.license = "MIT"
16
15
 
17
16
  if spec.respond_to?(:metadata)
18
- spec.metadata['allowed_push_host'] = "https://rubygems.org"
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
19
18
  else
20
19
  raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
21
20
  end
@@ -25,9 +24,10 @@ Gem::Specification.new do |spec|
25
24
  spec.executables = spec.files.grep(%r{^bin/}) { |filename| File.basename(filename) }
26
25
  spec.require_paths = ["lib"]
27
26
 
28
- spec.required_ruby_version = '~> 2.5'
27
+ spec.required_ruby_version = "~> 3.0"
29
28
 
30
- spec.add_runtime_dependency 'tty-prompt', '~> 0.20'
29
+ spec.add_runtime_dependency "tty-prompt", "~> 0.20"
31
30
 
32
- spec.add_development_dependency 'rspec', '~> 3.0'
31
+ spec.add_development_dependency "rspec", "~> 3.0"
32
+ spec.add_development_dependency "rubocop", "~> 0.79"
33
33
  end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v1.3.0
4
+
5
+ * Support Ruby version 3
6
+ * Fix comment listing (#86)
7
+
8
+ ## v1.2.0
9
+
10
+ * Support running multiple commands with `--init` switch (#83)
11
+ * Include current board name to status line (#77)
12
+ * Introduce `card add-label` command (#74)
13
+ * Support multiline card description (#72)
14
+
15
+ ## v1.1.0
16
+
17
+ * Introduce "list add" command.
18
+ * Introduce "board add" command.
19
+ * Introduce label related command.
20
+ * Support exiting with Ctrl+D.
21
+
3
22
  ## v1.0.0
4
23
 
5
24
  * Support using shortcuts to access entities.
@@ -10,6 +29,8 @@
10
29
  * Improve performance of several commands.
11
30
  * Support checklist related commands.
12
31
  * Support Ruby 2.5+.
32
+ * Introduce `card edit` command.
33
+ * Improve command auto completion.
13
34
 
14
35
  ## v0.3.1
15
36
 
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in trecli.gemspec
4
4
  gemspec
5
5
 
6
- gem 'bundler'
7
- gem 'rake'
6
+ gem "bundler"
7
+ gem "rake"
data/LICENSE CHANGED
@@ -1,6 +1,7 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2017-2020 Cẩm Huỳnh
3
+ Copyright (c) 2017 Cẩm Huỳnh
4
+ Copyright (c) 2020 Cẩm Huỳnh and Diệp Sở Hùng
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
7
  of this software and associated documentation files (the "Software"), to deal
data/Rakefile CHANGED
@@ -1,10 +1,4 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ require "rspec/core/rake_task"
2
+ RSpec::Core::RakeTask.new(:spec)
3
3
 
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList['test/**/*_test.rb']
8
- end
9
-
10
- task :default => :test
4
+ task default: :spec
data/bin/3llo CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $:.unshift File.expand_path("../../lib", __FILE__)
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
4
  require "3llo"
5
- require 'container'
6
- require 'tty-prompt'
7
- require 'optparse'
5
+ require "container"
6
+ require "tty-prompt"
7
+ require "optparse"
8
8
 
9
9
  Tr3llo::Application.start(ARGV)
@@ -4,44 +4,40 @@ module Tr3llo
4
4
  extend self
5
5
 
6
6
  def find_all_by_user(user_id)
7
- JSON.parse(
8
- client.get(
7
+ client = Application.fetch_client!()
8
+ req_path =
9
+ Utils.build_req_path(
9
10
  "/members/#{user_id}/boards",
10
- key: api_key,
11
- token: api_token,
12
- filter: "open"
11
+ {"filter" => "open"}
13
12
  )
14
- ).map do |board_payload|
15
- make_struct(board_payload)
16
- end
13
+
14
+ client
15
+ .get(req_path, {})
16
+ .map do |board_payload|
17
+ make_struct(board_payload)
18
+ end
17
19
  end
18
20
 
19
21
  def find(board_id)
20
- payload =
21
- JSON.parse(
22
- client.get(
23
- "/boards/#{board_id}",
24
- key: api_key,
25
- token: api_token,
26
- )
27
- )
22
+ client = Application.fetch_client!()
23
+ req_path = Utils.build_req_path("/boards/#{board_id}")
28
24
 
29
- make_struct(payload)
25
+ make_struct(client.get(req_path, {}))
30
26
  end
31
27
 
32
- private
28
+ def create(name:, desc:, default_lists: true)
29
+ client = Application.fetch_client!()
30
+ req_path = Utils.build_req_path("/boards", {})
31
+ payload = {
32
+ "name" => name,
33
+ "desc" => desc,
34
+ "defaultLists" => default_lists
35
+ }
33
36
 
34
- def client
35
- Application.fetch_client!()
37
+ client.post(req_path, {}, payload)
36
38
  end
37
39
 
38
- def api_key
39
- Application.fetch_configuration!().api_key
40
- end
41
-
42
- def api_token
43
- Application.fetch_configuration!().api_token
44
- end
40
+ private
45
41
 
46
42
  def make_struct(payload)
47
43
  id, name = payload.fetch_values("id", "name")
data/lib/3llo/api/card.rb CHANGED
@@ -4,131 +4,122 @@ module Tr3llo
4
4
  extend self
5
5
 
6
6
  def find_all_by_list(list_id)
7
- JSON.parse(
8
- client.get(
7
+ req_path =
8
+ Utils.build_req_path(
9
9
  "/lists/#{list_id}/cards",
10
- key: api_key,
11
- token: api_token,
12
- members: 'true',
13
- member_fields: "id,username"
10
+ {"members" => "true", "member_fields" => "id,username"}
14
11
  )
15
- ).map do |card_payload|
16
- make_struct(card_payload)
17
- end
12
+
13
+ client
14
+ .get(req_path, {})
15
+ .map do |card_payload|
16
+ make_struct(card_payload)
17
+ end
18
18
  end
19
19
 
20
20
  def find_all_by_user(board_id, user_id)
21
- JSON.parse(
22
- client.get(
21
+ req_path =
22
+ Utils.build_req_path(
23
23
  "/boards/#{board_id}/members/#{user_id}/cards",
24
- list: true,
25
- key: api_key,
26
- token: api_token
24
+ {"list" => "true"}
27
25
  )
28
- ).map do |card_payload|
29
- make_struct(card_payload)
30
- end
26
+
27
+ client
28
+ .get(req_path, {})
29
+ .map do |card_payload|
30
+ make_struct(card_payload)
31
+ end
31
32
  end
32
33
 
33
34
  def create(name, description, list_id)
34
- client.post(
35
- "/cards",
36
- key: api_key,
37
- token: api_token,
38
- name: name,
39
- desc: description,
40
- idList: list_id
41
- )
35
+ req_path = Utils.build_req_path("/cards", {})
36
+ payload = {
37
+ "name" => name,
38
+ "desc" => description,
39
+ "idList" => list_id
40
+ }
41
+
42
+ client.post(req_path, {}, payload)
43
+ end
44
+
45
+ def update(card_id, data)
46
+ req_path = Utils.build_req_path("/cards/#{card_id}")
47
+
48
+ client.put(req_path, {}, data)
42
49
  end
43
50
 
44
51
  def find(card_id)
45
- card_payload =
46
- JSON.parse(
47
- client.get(
48
- "/cards/#{card_id}",
49
- list: true,
50
- members: true,
51
- key: api_key,
52
- token: api_token
53
- )
52
+ req_path =
53
+ Utils.build_req_path(
54
+ "/cards/#{card_id}",
55
+ {"list" => "true", "members" => "true"}
54
56
  )
55
57
 
58
+ card_payload = client.get(req_path, {})
59
+
56
60
  make_struct(card_payload)
57
61
  end
58
62
 
63
+ # TODO: Use ".update".
59
64
  def move_to_list(card_id, list_id)
60
- url = "/cards/#{card_id}/idList"
61
- JSON.parse(
62
- client.put(
63
- url,
64
- key: api_key,
65
- token: api_token,
66
- value: list_id
67
- )
68
- )
65
+ req_path = Utils.build_req_path("/cards/#{card_id}/idList")
66
+
67
+ client.put(req_path, {}, {"value" => list_id})
69
68
  end
70
69
 
70
+ # TODO: Use ".update".
71
71
  def assign_members(card_id, members)
72
- url = "/cards/#{card_id}/idMembers"
73
- JSON.parse(
74
- client.put(
75
- url,
76
- key: api_key,
77
- token: api_token,
78
- value: members.join(',')
79
- )
80
- )
72
+ req_path = Utils.build_req_path("/cards/#{card_id}/idMembers")
73
+
74
+ client.put(req_path, {}, {"value" => members.join(",")})
81
75
  end
82
76
 
83
77
  def list_comments(card_id)
84
- url = "/cards/#{card_id}/actions"
85
-
86
- JSON.parse(
87
- client.get(
88
- url,
89
- key: api_key,
90
- token: api_token,
91
- filter: "commentCard",
78
+ req_path =
79
+ Utils.build_req_path(
80
+ "/cards/#{card_id}/actions",
81
+ {"filter" => "commentCard"}
92
82
  )
93
- ).map do |comment_payload|
94
- id, creator_payload, date = comment_payload.fetch_values("id", "memberCreator", "date")
95
- text = comment_payload.dig("data", "text")
96
83
 
97
- created_at = DateTime.iso8601(date)
84
+ client
85
+ .get(req_path, {})
86
+ .map do |comment_payload|
87
+ id, creator_payload, date = comment_payload.fetch_values("id", "memberCreator", "date")
88
+ text = comment_payload.dig("data", "text")
98
89
 
99
- creator_id, creator_username = creator_payload.fetch_values("id", "username")
100
- creator = Entities::User.new(creator_id, _creator_shortcut = nil, creator_username)
90
+ created_at = DateTime.iso8601(date)
101
91
 
102
- Entities::Comment.new(
103
- id: id,
104
- creator: creator,
105
- created_at: created_at,
106
- text: text
107
- )
108
- end
92
+ creator_id, creator_username = creator_payload.fetch_values("id", "username")
93
+ creator = Entities::User.new(creator_id, _creator_shortcut = nil, creator_username)
94
+
95
+ Entities::Comment.new(
96
+ id: id,
97
+ creator: creator,
98
+ created_at: created_at,
99
+ text: text
100
+ )
101
+ end
109
102
  end
110
103
 
111
104
  def comment(card_id, text)
112
- url = "/cards/#{card_id}/actions/comments"
113
- JSON.parse(
114
- client.post(
115
- url,
116
- key: api_key,
117
- token: api_token,
118
- text: text
119
- )
120
- )
105
+ req_path = Utils.build_req_path("/cards/#{card_id}/actions/comments")
106
+ payload = {"text" => text}
107
+
108
+ client.post(req_path, {}, payload)
121
109
  end
122
110
 
111
+ # TODO: Use ".update".
123
112
  def archive(card_id)
124
- url = "/cards/#{card_id}?closed=true"
125
- JSON.parse(
126
- client.put(
127
- url,
128
- key: api_key,
129
- token: api_token
130
- )
131
- )
113
+ req_path = Utils.build_req_path("/cards/#{card_id}")
114
+ payload = {"closed" => "true"}
115
+
116
+ client.put(req_path, {}, payload)
117
+ end
118
+
119
+ def add_labels(card_id, labels)
120
+ req_path = Utils.build_req_path("/cards/#{card_id}/idLabels")
121
+
122
+ client.put(req_path, {}, {"value" => labels.join(",")})
132
123
  end
133
124
 
134
125
  private
@@ -139,8 +130,8 @@ module Tr3llo
139
130
 
140
131
  members =
141
132
  payload
142
- .fetch("members", [])
143
- .map do |member_payload|
133
+ .fetch("members", [])
134
+ .map do |member_payload|
144
135
  user_id, username = member_payload.fetch_values("id", "username")
145
136
 
146
137
  Entities::User.new(user_id, _user_shortcut = nil, username)
@@ -148,12 +139,13 @@ module Tr3llo
148
139
 
149
140
  labels =
150
141
  payload
151
- .fetch("labels", [])
152
- .map do |label_payload|
142
+ .fetch("labels", [])
143
+ .map do |label_payload|
144
+ label_id = label_payload.fetch("id")
153
145
  label_name = label_payload.fetch("name")
154
146
  label_color = label_payload["color"]
155
147
 
156
- Entities::Label.new(label_name, label_color)
148
+ Entities::Label.new(id: label_id, shortcut: nil, name: label_name, color: label_color)
157
149
  end
158
150
 
159
151
  card =
@@ -175,14 +167,6 @@ module Tr3llo
175
167
  card
176
168
  end
177
169
 
178
- def api_key
179
- Application.fetch_configuration!().api_key
180
- end
181
-
182
- def api_token
183
- Application.fetch_configuration!().api_token
184
- end
185
-
186
170
  def client
187
171
  Application.fetch_client!()
188
172
  end