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

Sign up to get free protection for your applications and to get access to all the features.
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