fizzy-cli 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +17 -0
- data/LICENSE.txt +21 -0
- data/README.md +194 -0
- data/bin/fizzy +13 -0
- data/lib/fizzy/auth.rb +37 -0
- data/lib/fizzy/cli/auth.rb +110 -0
- data/lib/fizzy/cli/base.rb +68 -0
- data/lib/fizzy/cli/boards.rb +57 -0
- data/lib/fizzy/cli/cards.rb +178 -0
- data/lib/fizzy/cli/columns.rb +61 -0
- data/lib/fizzy/cli/comments.rb +61 -0
- data/lib/fizzy/cli/notifications.rb +42 -0
- data/lib/fizzy/cli/pins.rb +30 -0
- data/lib/fizzy/cli/reactions.rb +49 -0
- data/lib/fizzy/cli/steps.rb +55 -0
- data/lib/fizzy/cli/tags.rb +17 -0
- data/lib/fizzy/cli/users.rb +50 -0
- data/lib/fizzy/cli.rb +62 -0
- data/lib/fizzy/client.rb +124 -0
- data/lib/fizzy/errors.rb +21 -0
- data/lib/fizzy/formatter.rb +37 -0
- data/lib/fizzy/paginator.rb +43 -0
- data/lib/fizzy/version.rb +5 -0
- data/lib/fizzy.rb +13 -0
- metadata +88 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Cards < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "list", "List cards"
|
|
9
|
+
option :board, desc: "Board ID (filter)"
|
|
10
|
+
option :column, desc: "Column ID (filter)"
|
|
11
|
+
option :status, desc: "Filter: open, closed, all", default: "open"
|
|
12
|
+
option :assignee, desc: "Assignee user ID (filter)"
|
|
13
|
+
option :tag, desc: "Tag ID (filter, repeatable)", type: :array
|
|
14
|
+
def list
|
|
15
|
+
params = {}
|
|
16
|
+
params[:status] = options[:status] if options[:status]
|
|
17
|
+
params[:board_id] = options[:board] if options[:board]
|
|
18
|
+
params[:column_id] = options[:column] if options[:column]
|
|
19
|
+
params[:assignee_id] = options[:assignee] if options[:assignee]
|
|
20
|
+
options[:tag]&.each { |t| (params[:"tag_ids[]"] ||= []) << t }
|
|
21
|
+
|
|
22
|
+
data = paginator.all("#{slug}/cards", params: params)
|
|
23
|
+
output_list(data, headers: %w[# Title Board Status Column]) do |c|
|
|
24
|
+
[
|
|
25
|
+
c["number"],
|
|
26
|
+
Formatter.truncate(c["title"], 50),
|
|
27
|
+
c.dig("board", "name") || "",
|
|
28
|
+
c["status"],
|
|
29
|
+
c.dig("column", "name") || ""
|
|
30
|
+
]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
desc "get NUMBER", "Show a card"
|
|
35
|
+
def get(number)
|
|
36
|
+
resp = client.get("#{slug}/cards/#{number}")
|
|
37
|
+
c = resp.body
|
|
38
|
+
output_detail(c, pairs: [
|
|
39
|
+
["Number", "##{c["number"]}"],
|
|
40
|
+
["Title", c["title"]],
|
|
41
|
+
["Board", c.dig("board", "name")],
|
|
42
|
+
["Column", c.dig("column", "name")],
|
|
43
|
+
["Status", c["status"]],
|
|
44
|
+
["Creator", c.dig("creator", "name")],
|
|
45
|
+
["Assignees", format_assignees(c["assignees"])],
|
|
46
|
+
["Tags", format_tags(c["tags"])],
|
|
47
|
+
["Steps", format_steps(c["steps"])],
|
|
48
|
+
["Created", c["created_at"]],
|
|
49
|
+
["URL", c["url"]]
|
|
50
|
+
])
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
desc "create TITLE", "Create a card"
|
|
54
|
+
option :board, required: true, desc: "Board ID"
|
|
55
|
+
option :body, desc: "Card body (HTML)"
|
|
56
|
+
option :column, desc: "Column ID"
|
|
57
|
+
def create(title)
|
|
58
|
+
body = { title: title }
|
|
59
|
+
body[:body] = options[:body] if options[:body]
|
|
60
|
+
body[:column_id] = options[:column] if options[:column]
|
|
61
|
+
resp = client.post("#{slug}/boards/#{options[:board]}/cards", body: body)
|
|
62
|
+
c = resp.body
|
|
63
|
+
output_detail(c, pairs: [
|
|
64
|
+
["Number", "##{c["number"]}"],
|
|
65
|
+
["Title", c["title"]],
|
|
66
|
+
["URL", c["url"]]
|
|
67
|
+
])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
desc "update NUMBER", "Update a card"
|
|
71
|
+
option :title, desc: "New title"
|
|
72
|
+
option :body, desc: "New body (HTML)"
|
|
73
|
+
def update(number)
|
|
74
|
+
resp = client.put("#{slug}/cards/#{number}", body: build_body(:title, :body))
|
|
75
|
+
c = resp.body
|
|
76
|
+
output_detail(c, pairs: [
|
|
77
|
+
["Number", "##{c["number"]}"],
|
|
78
|
+
["Title", c["title"]]
|
|
79
|
+
])
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
desc "delete NUMBER", "Delete a card"
|
|
83
|
+
def delete(number)
|
|
84
|
+
client.delete("#{slug}/cards/#{number}")
|
|
85
|
+
puts "Card ##{number} deleted."
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
desc "close NUMBER", "Close a card"
|
|
89
|
+
def close(number)
|
|
90
|
+
client.post("#{slug}/cards/#{number}/closure")
|
|
91
|
+
puts "Card ##{number} closed."
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
desc "reopen NUMBER", "Reopen a closed card"
|
|
95
|
+
def reopen(number)
|
|
96
|
+
client.delete("#{slug}/cards/#{number}/closure")
|
|
97
|
+
puts "Card ##{number} reopened."
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
desc "not-now NUMBER", "Mark a card as not-now"
|
|
101
|
+
map "not-now" => :not_now
|
|
102
|
+
def not_now(number)
|
|
103
|
+
client.post("#{slug}/cards/#{number}/not_now")
|
|
104
|
+
puts "Card ##{number} marked not-now."
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
desc "triage NUMBER", "Triage a card into a column"
|
|
108
|
+
option :column, required: true, desc: "Column ID"
|
|
109
|
+
def triage(number)
|
|
110
|
+
client.post("#{slug}/cards/#{number}/triage", body: { column_id: options[:column] })
|
|
111
|
+
puts "Card ##{number} triaged."
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
desc "untriage NUMBER", "Remove a card from triage"
|
|
115
|
+
def untriage(number)
|
|
116
|
+
client.delete("#{slug}/cards/#{number}/triage")
|
|
117
|
+
puts "Card ##{number} untriaged."
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
desc "tag NUMBER TAG_TITLE", "Add a tag to a card"
|
|
121
|
+
def tag(number, tag_title)
|
|
122
|
+
client.post("#{slug}/cards/#{number}/taggings", body: { tag_title: tag_title })
|
|
123
|
+
puts "Tag '#{tag_title}' added to card ##{number}."
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
desc "assign NUMBER ASSIGNEE_ID", "Toggle assignment on a card"
|
|
127
|
+
def assign(number, assignee_id)
|
|
128
|
+
client.post("#{slug}/cards/#{number}/assignments", body: { assignee_id: assignee_id })
|
|
129
|
+
puts "Assignment toggled for card ##{number}."
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
desc "watch NUMBER", "Watch a card"
|
|
133
|
+
def watch(number)
|
|
134
|
+
client.post("#{slug}/cards/#{number}/watch")
|
|
135
|
+
puts "Watching card ##{number}."
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
desc "unwatch NUMBER", "Unwatch a card"
|
|
139
|
+
def unwatch(number)
|
|
140
|
+
client.delete("#{slug}/cards/#{number}/watch")
|
|
141
|
+
puts "Unwatched card ##{number}."
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
desc "golden NUMBER", "Mark a card as golden"
|
|
145
|
+
def golden(number)
|
|
146
|
+
client.post("#{slug}/cards/#{number}/goldness")
|
|
147
|
+
puts "Card ##{number} marked golden."
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
desc "ungolden NUMBER", "Remove golden from a card"
|
|
151
|
+
def ungolden(number)
|
|
152
|
+
client.delete("#{slug}/cards/#{number}/goldness")
|
|
153
|
+
puts "Card ##{number} ungolden."
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def format_assignees(assignees)
|
|
159
|
+
return "" unless assignees&.any?
|
|
160
|
+
|
|
161
|
+
assignees.map { |a| a["name"] }.join(", ")
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def format_tags(tags)
|
|
165
|
+
return "" unless tags&.any?
|
|
166
|
+
|
|
167
|
+
tags.map { |t| t["title"] || t["name"] }.join(", ")
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def format_steps(steps)
|
|
171
|
+
return "" unless steps&.any?
|
|
172
|
+
|
|
173
|
+
done = steps.count { |s| s["completed"] }
|
|
174
|
+
"#{done}/#{steps.size}"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Columns < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "list", "List columns for a board"
|
|
9
|
+
option :board, required: true, desc: "Board ID"
|
|
10
|
+
def list
|
|
11
|
+
data = paginator.all("#{slug}/boards/#{options[:board]}/columns")
|
|
12
|
+
output_list(data, headers: %w[ID Name Position]) do |c|
|
|
13
|
+
[c["id"], c["name"], c["position"]]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "get COLUMN_ID", "Show a column"
|
|
18
|
+
option :board, required: true, desc: "Board ID"
|
|
19
|
+
def get(column_id)
|
|
20
|
+
resp = client.get("#{slug}/boards/#{options[:board]}/columns/#{column_id}")
|
|
21
|
+
c = resp.body
|
|
22
|
+
output_detail(c, pairs: [
|
|
23
|
+
["ID", c["id"]],
|
|
24
|
+
["Name", c["name"]],
|
|
25
|
+
["Position", c["position"]],
|
|
26
|
+
["Created", c["created_at"]]
|
|
27
|
+
])
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
desc "create NAME", "Create a column"
|
|
31
|
+
option :board, required: true, desc: "Board ID"
|
|
32
|
+
def create(name)
|
|
33
|
+
resp = client.post("#{slug}/boards/#{options[:board]}/columns", body: { name: name })
|
|
34
|
+
c = resp.body
|
|
35
|
+
output_detail(c, pairs: [
|
|
36
|
+
["ID", c["id"]],
|
|
37
|
+
["Name", c["name"]]
|
|
38
|
+
])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
desc "update COLUMN_ID", "Update a column"
|
|
42
|
+
option :board, required: true, desc: "Board ID"
|
|
43
|
+
option :name, required: true, desc: "New column name"
|
|
44
|
+
def update(column_id)
|
|
45
|
+
resp = client.put("#{slug}/boards/#{options[:board]}/columns/#{column_id}", body: { name: options[:name] })
|
|
46
|
+
c = resp.body
|
|
47
|
+
output_detail(c, pairs: [
|
|
48
|
+
["ID", c["id"]],
|
|
49
|
+
["Name", c["name"]]
|
|
50
|
+
])
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
desc "delete COLUMN_ID", "Delete a column"
|
|
54
|
+
option :board, required: true, desc: "Board ID"
|
|
55
|
+
def delete(column_id)
|
|
56
|
+
client.delete("#{slug}/boards/#{options[:board]}/columns/#{column_id}")
|
|
57
|
+
puts "Column #{column_id} deleted."
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Comments < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "list", "List comments on a card"
|
|
9
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
10
|
+
def list
|
|
11
|
+
data = paginator.all("#{slug}/cards/#{options[:card]}/comments")
|
|
12
|
+
output_list(data, headers: %w[ID Author Created]) do |c|
|
|
13
|
+
[c["id"], c.dig("creator", "name"), c["created_at"]]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "get COMMENT_ID", "Show a comment"
|
|
18
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
19
|
+
def get(comment_id)
|
|
20
|
+
resp = client.get("#{slug}/cards/#{options[:card]}/comments/#{comment_id}")
|
|
21
|
+
c = resp.body
|
|
22
|
+
output_detail(c, pairs: [
|
|
23
|
+
["ID", c["id"]],
|
|
24
|
+
["Author", c.dig("creator", "name")],
|
|
25
|
+
["Body", c["body"]],
|
|
26
|
+
["Created", c["created_at"]]
|
|
27
|
+
])
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
desc "create BODY", "Add a comment to a card"
|
|
31
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
32
|
+
def create(body_text)
|
|
33
|
+
resp = client.post("#{slug}/cards/#{options[:card]}/comments", body: { body: body_text })
|
|
34
|
+
c = resp.body
|
|
35
|
+
output_detail(c, pairs: [
|
|
36
|
+
["ID", c["id"]],
|
|
37
|
+
["Body", c["body"]]
|
|
38
|
+
])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
desc "update COMMENT_ID", "Update a comment"
|
|
42
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
43
|
+
option :body, required: true, desc: "New body"
|
|
44
|
+
def update(comment_id)
|
|
45
|
+
resp = client.put("#{slug}/cards/#{options[:card]}/comments/#{comment_id}", body: build_body(:body))
|
|
46
|
+
c = resp.body
|
|
47
|
+
output_detail(c, pairs: [
|
|
48
|
+
["ID", c["id"]],
|
|
49
|
+
["Body", c["body"]]
|
|
50
|
+
])
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
desc "delete COMMENT_ID", "Delete a comment"
|
|
54
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
55
|
+
def delete(comment_id)
|
|
56
|
+
client.delete("#{slug}/cards/#{options[:card]}/comments/#{comment_id}")
|
|
57
|
+
puts "Comment #{comment_id} deleted."
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Notifications < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "list", "List notifications"
|
|
9
|
+
def list
|
|
10
|
+
data = paginator.all("#{slug}/notifications")
|
|
11
|
+
output_list(data, headers: %w[ID Type Card Read Created]) do |n|
|
|
12
|
+
[
|
|
13
|
+
n["id"],
|
|
14
|
+
n["event_type"],
|
|
15
|
+
n.dig("card", "title") || "",
|
|
16
|
+
n["read_at"] ? "yes" : "no",
|
|
17
|
+
n["created_at"]
|
|
18
|
+
]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc "read ID", "Mark notification as read"
|
|
23
|
+
def read(id)
|
|
24
|
+
client.post("#{slug}/notifications/#{id}/reading")
|
|
25
|
+
puts "Notification #{id} marked read."
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
desc "unread ID", "Mark notification as unread"
|
|
29
|
+
def unread(id)
|
|
30
|
+
client.delete("#{slug}/notifications/#{id}/reading")
|
|
31
|
+
puts "Notification #{id} marked unread."
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
desc "mark-all-read", "Mark all notifications as read"
|
|
35
|
+
map "mark-all-read" => :mark_all_read
|
|
36
|
+
def mark_all_read
|
|
37
|
+
client.post("#{slug}/notifications/bulk_reading")
|
|
38
|
+
puts "All notifications marked read."
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Pins < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "list", "List pinned cards"
|
|
9
|
+
def list
|
|
10
|
+
data = paginator.all("/my/pins")
|
|
11
|
+
output_list(data, headers: %w[# Title Board]) do |p|
|
|
12
|
+
card = p["card"] || p
|
|
13
|
+
[card["number"], card["title"], card.dig("board", "name") || ""]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "pin NUMBER", "Pin a card"
|
|
18
|
+
def pin(number)
|
|
19
|
+
client.post("#{slug}/cards/#{number}/pin")
|
|
20
|
+
puts "Card ##{number} pinned."
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc "unpin NUMBER", "Unpin a card"
|
|
24
|
+
def unpin(number)
|
|
25
|
+
client.delete("#{slug}/cards/#{number}/pin")
|
|
26
|
+
puts "Card ##{number} unpinned."
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Reactions < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "list", "List reactions on a card"
|
|
9
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
10
|
+
option :comment, desc: "Comment ID (for comment reactions)"
|
|
11
|
+
def list
|
|
12
|
+
path = reaction_path(options[:card], options[:comment])
|
|
13
|
+
data = paginator.all(path)
|
|
14
|
+
output_list(data, headers: %w[ID Content User]) do |r|
|
|
15
|
+
[r["id"], r["content"], r.dig("creator", "name")]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
desc "create CONTENT", "Add a reaction"
|
|
20
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
21
|
+
option :comment, desc: "Comment ID (for comment reactions)"
|
|
22
|
+
def create(content)
|
|
23
|
+
path = reaction_path(options[:card], options[:comment])
|
|
24
|
+
resp = client.post(path, body: { content: content })
|
|
25
|
+
r = resp.body
|
|
26
|
+
output_detail(r, pairs: [
|
|
27
|
+
["ID", r["id"]],
|
|
28
|
+
["Content", r["content"]]
|
|
29
|
+
])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "delete REACTION_ID", "Remove a reaction"
|
|
33
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
34
|
+
option :comment, desc: "Comment ID (for comment reactions)"
|
|
35
|
+
def delete(reaction_id)
|
|
36
|
+
path = "#{reaction_path(options[:card], options[:comment])}/#{reaction_id}"
|
|
37
|
+
client.delete(path)
|
|
38
|
+
puts "Reaction #{reaction_id} deleted."
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def reaction_path(card_number, comment_id = nil)
|
|
44
|
+
base = "#{slug}/cards/#{card_number}"
|
|
45
|
+
comment_id ? "#{base}/comments/#{comment_id}/reactions" : "#{base}/reactions"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Steps < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "get STEP_ID", "Show a step"
|
|
9
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
10
|
+
def get(step_id)
|
|
11
|
+
resp = client.get("#{slug}/cards/#{options[:card]}/steps/#{step_id}")
|
|
12
|
+
s = resp.body
|
|
13
|
+
output_detail(s, pairs: [
|
|
14
|
+
["ID", s["id"]],
|
|
15
|
+
["Description", s["description"]],
|
|
16
|
+
["Completed", s["completed"]],
|
|
17
|
+
["Position", s["position"]]
|
|
18
|
+
])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
desc "create DESCRIPTION", "Add a step to a card"
|
|
22
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
23
|
+
def create(description)
|
|
24
|
+
resp = client.post("#{slug}/cards/#{options[:card]}/steps", body: { description: description })
|
|
25
|
+
s = resp.body
|
|
26
|
+
output_detail(s, pairs: [
|
|
27
|
+
["ID", s["id"]],
|
|
28
|
+
["Description", s["description"]]
|
|
29
|
+
])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc "update STEP_ID", "Update a step"
|
|
33
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
34
|
+
option :description, desc: "New description"
|
|
35
|
+
option :completed, type: :boolean, desc: "Mark completed"
|
|
36
|
+
def update(step_id)
|
|
37
|
+
path = "#{slug}/cards/#{options[:card]}/steps/#{step_id}"
|
|
38
|
+
resp = client.put(path, body: build_body(:description, :completed))
|
|
39
|
+
s = resp.body
|
|
40
|
+
output_detail(s, pairs: [
|
|
41
|
+
["ID", s["id"]],
|
|
42
|
+
["Description", s["description"]],
|
|
43
|
+
["Completed", s["completed"]]
|
|
44
|
+
])
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
desc "delete STEP_ID", "Delete a step"
|
|
48
|
+
option :card, required: true, type: :numeric, desc: "Card number"
|
|
49
|
+
def delete(step_id)
|
|
50
|
+
client.delete("#{slug}/cards/#{options[:card]}/steps/#{step_id}")
|
|
51
|
+
puts "Step #{step_id} deleted."
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Tags < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "list", "List all tags"
|
|
9
|
+
def list
|
|
10
|
+
data = paginator.all("#{slug}/tags")
|
|
11
|
+
output_list(data, headers: %w[ID Title Color]) do |t|
|
|
12
|
+
[t["id"], t["title"] || t["name"], t["color"]]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Fizzy
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
class Users < Thor
|
|
6
|
+
include Base
|
|
7
|
+
|
|
8
|
+
desc "list", "List users"
|
|
9
|
+
def list
|
|
10
|
+
data = paginator.all("#{slug}/users")
|
|
11
|
+
output_list(data, headers: %w[ID Name Email Role Active]) do |u|
|
|
12
|
+
[u["id"], u["name"], u["email_address"], u["role"], u["active"]]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc "get USER_ID", "Show a user"
|
|
17
|
+
def get(user_id)
|
|
18
|
+
resp = client.get("#{slug}/users/#{user_id}")
|
|
19
|
+
u = resp.body
|
|
20
|
+
output_detail(u, pairs: [
|
|
21
|
+
["ID", u["id"]],
|
|
22
|
+
["Name", u["name"]],
|
|
23
|
+
["Email", u["email_address"]],
|
|
24
|
+
["Role", u["role"]],
|
|
25
|
+
["Active", u["active"]],
|
|
26
|
+
["Created", u["created_at"]]
|
|
27
|
+
])
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
desc "update USER_ID", "Update a user"
|
|
31
|
+
option :name, desc: "New name"
|
|
32
|
+
option :role, desc: "New role"
|
|
33
|
+
def update(user_id)
|
|
34
|
+
resp = client.put("#{slug}/users/#{user_id}", body: build_body(:name, :role))
|
|
35
|
+
u = resp.body
|
|
36
|
+
output_detail(u, pairs: [
|
|
37
|
+
["ID", u["id"]],
|
|
38
|
+
["Name", u["name"]],
|
|
39
|
+
["Role", u["role"]]
|
|
40
|
+
])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
desc "deactivate USER_ID", "Deactivate a user"
|
|
44
|
+
def deactivate(user_id)
|
|
45
|
+
client.delete("#{slug}/users/#{user_id}")
|
|
46
|
+
puts "User #{user_id} deactivated."
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/fizzy/cli.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "thor"
|
|
4
|
+
require_relative "cli/base"
|
|
5
|
+
require_relative "cli/boards"
|
|
6
|
+
require_relative "cli/cards"
|
|
7
|
+
require_relative "cli/columns"
|
|
8
|
+
require_relative "cli/steps"
|
|
9
|
+
require_relative "cli/comments"
|
|
10
|
+
require_relative "cli/reactions"
|
|
11
|
+
require_relative "cli/tags"
|
|
12
|
+
require_relative "cli/users"
|
|
13
|
+
require_relative "cli/notifications"
|
|
14
|
+
require_relative "cli/pins"
|
|
15
|
+
require_relative "cli/auth"
|
|
16
|
+
|
|
17
|
+
module Fizzy
|
|
18
|
+
class CLI < Thor
|
|
19
|
+
class_option :json, type: :boolean, desc: "Output as JSON"
|
|
20
|
+
class_option :account, type: :string, desc: "Account slug override"
|
|
21
|
+
|
|
22
|
+
desc "version", "Print version"
|
|
23
|
+
def version
|
|
24
|
+
puts "fizzy-cli #{VERSION}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc "boards SUBCOMMAND ...ARGS", "Manage boards"
|
|
28
|
+
subcommand "boards", CLI::Boards
|
|
29
|
+
|
|
30
|
+
desc "cards SUBCOMMAND ...ARGS", "Manage cards"
|
|
31
|
+
subcommand "cards", CLI::Cards
|
|
32
|
+
|
|
33
|
+
desc "columns SUBCOMMAND ...ARGS", "Manage columns"
|
|
34
|
+
subcommand "columns", CLI::Columns
|
|
35
|
+
|
|
36
|
+
desc "steps SUBCOMMAND ...ARGS", "Manage card steps"
|
|
37
|
+
subcommand "steps", CLI::Steps
|
|
38
|
+
|
|
39
|
+
desc "comments SUBCOMMAND ...ARGS", "Manage card comments"
|
|
40
|
+
subcommand "comments", CLI::Comments
|
|
41
|
+
|
|
42
|
+
desc "reactions SUBCOMMAND ...ARGS", "Manage reactions"
|
|
43
|
+
subcommand "reactions", CLI::Reactions
|
|
44
|
+
|
|
45
|
+
desc "tags SUBCOMMAND ...ARGS", "List tags"
|
|
46
|
+
subcommand "tags", CLI::Tags
|
|
47
|
+
|
|
48
|
+
desc "users SUBCOMMAND ...ARGS", "Manage users"
|
|
49
|
+
subcommand "users", CLI::Users
|
|
50
|
+
|
|
51
|
+
desc "notifications SUBCOMMAND ...ARGS", "Manage notifications"
|
|
52
|
+
subcommand "notifications", CLI::Notifications
|
|
53
|
+
|
|
54
|
+
desc "pins SUBCOMMAND ...ARGS", "Manage pinned cards"
|
|
55
|
+
subcommand "pins", CLI::Pins
|
|
56
|
+
|
|
57
|
+
desc "auth SUBCOMMAND ...ARGS", "Authentication commands"
|
|
58
|
+
subcommand "auth", CLI::AuthCommands
|
|
59
|
+
|
|
60
|
+
def self.exit_on_failure? = true
|
|
61
|
+
end
|
|
62
|
+
end
|