fizzy-cli 0.4.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca34b7cb72db62ab1659d5210eb4463496870cf817c88fa58321e7443a630ad3
4
- data.tar.gz: 8d653993a4bb9bc85079f2b16c1f0c84d496abaab50c15c6ed5e9443fd16b089
3
+ metadata.gz: fe63e297523bda1dd7bf9a33e63500c79b69908f0beff894e9ac46c1417dcb50
4
+ data.tar.gz: 1a212a6743312655d388622c5af175325b61defcf8dd56076c29b1a2fa5b86e3
5
5
  SHA512:
6
- metadata.gz: 1152c52e0574fc5b9cb4f499de24e3cceaf046d2cdddc4f6a20f8d2eac1def18ebec9adf36be0f7f0aa61acbdcc24ef6b7353b04e0ecc61a58faba907b0157ec
7
- data.tar.gz: 0a64fd82e2b22f214cf73a1770f3a373cc461986f521485311d27c8914d4d0948c6be68ae91252f103d27655f4f59dccc6b35adf47491d024bdaafd9e57df2e2
6
+ metadata.gz: e248468298d49a352c3ffe24542bee9fe5c4501487a970c4c365081ca8505423bcd90f0e8f0dafc42e05f88fbca917633cfab82b1e02b39202f9393f2bdfe1ed
7
+ data.tar.gz: 54322d6c4d43d3c528e83a124514d214d58501d4f7ee31378430af636893463c4dbb64f42ac25aa31f2a6231f7c07d09098f372560e508228dcdfbe8ece9d522
data/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [0.5.0] - 2026-02-22
9
+
10
+ ### Added
11
+ - Cache boards in `.fizzy.yml` as `boards: { id: name }` hash for quick lookups without API calls
12
+ - `fizzy boards sync` command to refresh the cached boards list from the API
13
+ - `fizzy init` now automatically fetches and caches all boards during setup
14
+ - `ProjectConfig#boards` accessor for reading cached board data
15
+
16
+ ## [0.4.1] - 2026-02-22
17
+
18
+ ### Fixed
19
+ - Card create and update sent `body` instead of `description`, causing API 400 errors (field silently dropped by Rails strong params)
20
+ - Card create with `--column` now triages via separate API call instead of sending unpermitted `column_id` param
21
+ - HTTP 400 responses now get parsed error messages (like 422) instead of raw JSON dump
22
+ - Cards, steps, and users update commands validate at least one option is provided before sending empty request
23
+
24
+ ### Added
25
+ - `BadRequestError` class for explicit HTTP 400 handling
26
+
8
27
  ## [0.4.0] - 2026-02-22
9
28
 
10
29
  ### Added
@@ -56,6 +56,21 @@ module Fizzy
56
56
  client.delete("boards/#{board_id}")
57
57
  puts "Board #{board_id} deleted."
58
58
  end
59
+
60
+ desc "sync", "Refresh boards cache in .fizzy.yml"
61
+ def sync
62
+ raise Thor::Error, "No .fizzy.yml found. Run: fizzy init" unless project_config.found?
63
+
64
+ boards = paginator.all("boards")
65
+ boards_hash = boards.to_h { |b| [b["id"], b["name"]] }
66
+
67
+ config = YAML.safe_load_file(project_config.path)
68
+ config = {} unless config.is_a?(Hash)
69
+ config["boards"] = boards_hash
70
+
71
+ File.write(project_config.path, YAML.dump(config))
72
+ say "Synced #{boards_hash.size} board(s) to #{project_config.path}"
73
+ end
59
74
  end
60
75
  end
61
76
  end
@@ -55,11 +55,11 @@ module Fizzy
55
55
  option :body, desc: "Card body (HTML)"
56
56
  option :column, desc: "Column ID"
57
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("boards/#{require_board!}/cards", body: body)
58
+ payload = { title: title }
59
+ payload[:description] = options[:body] if options[:body]
60
+ resp = client.post("boards/#{require_board!}/cards", body: payload)
62
61
  c = resp.body
62
+ client.post("cards/#{c["number"]}/triage", body: { column_id: options[:column] }) if options[:column]
63
63
  output_detail(c, pairs: [
64
64
  ["Number", "##{c["number"]}"],
65
65
  ["Title", c["title"]],
@@ -71,7 +71,12 @@ module Fizzy
71
71
  option :title, desc: "New title"
72
72
  option :body, desc: "New body (HTML)"
73
73
  def update(number)
74
- resp = client.put("cards/#{number}", body: build_body(:title, :body))
74
+ payload = {}
75
+ payload[:title] = options[:title] if options[:title]
76
+ payload[:description] = options[:body] if options[:body]
77
+ raise Thor::Error, "Nothing to update. Provide --title or --body" if payload.empty?
78
+
79
+ resp = client.put("cards/#{number}", body: payload)
75
80
  c = resp.body
76
81
  if c
77
82
  output_detail(c, pairs: [
@@ -34,8 +34,11 @@ module Fizzy
34
34
  option :description, desc: "New description"
35
35
  option :completed, type: :boolean, desc: "Mark completed"
36
36
  def update(step_id)
37
+ body = build_body(:description, :completed)
38
+ raise Thor::Error, "Nothing to update. Provide --description or --completed" if body.empty?
39
+
37
40
  path = "cards/#{options[:card]}/steps/#{step_id}"
38
- resp = client.put(path, body: build_body(:description, :completed))
41
+ resp = client.put(path, body: body)
39
42
  s = resp.body
40
43
  if s
41
44
  output_detail(s, pairs: [
@@ -31,7 +31,10 @@ module Fizzy
31
31
  option :name, desc: "New name"
32
32
  option :role, desc: "New role"
33
33
  def update(user_id)
34
- resp = client.put("users/#{user_id}", body: build_body(:name, :role))
34
+ body = build_body(:name, :role)
35
+ raise Thor::Error, "Nothing to update. Provide --name or --role" if body.empty?
36
+
37
+ resp = client.put("users/#{user_id}", body: body)
35
38
  u = resp.body
36
39
  if u
37
40
  output_detail(u, pairs: [
data/lib/fizzy/cli.rb CHANGED
@@ -32,7 +32,10 @@ module Fizzy
32
32
 
33
33
  selected = pick_account
34
34
  config = { "account" => selected["account_slug"] }
35
- config["board"] = pick_board(selected) if yes?("Set a default board?")
35
+
36
+ boards = fetch_boards(selected)
37
+ config["boards"] = boards.to_h { |b| [b["id"], b["name"]] } if boards.any?
38
+ config["board"] = pick_board(boards) if boards.any? && yes?("Set a default board?")
36
39
 
37
40
  File.write(config_path, YAML.dump(config))
38
41
  say "Wrote #{config_path}"
@@ -97,15 +100,14 @@ module Fizzy
97
100
  accounts[idx]
98
101
  end
99
102
 
100
- def pick_board(account)
103
+ def fetch_boards(account)
101
104
  c = Client.new(token: account["access_token"], account_slug: account["account_slug"])
102
105
  boards = c.get("boards").body
106
+ say "No boards found." if boards.empty?
107
+ boards
108
+ end
103
109
 
104
- if boards.empty?
105
- say "No boards found."
106
- return nil
107
- end
108
-
110
+ def pick_board(boards)
109
111
  say "Boards:"
110
112
  boards.each_with_index do |b, i|
111
113
  say " #{i + 1}. #{b["name"]} (#{b["id"]})"
data/lib/fizzy/client.rb CHANGED
@@ -88,6 +88,8 @@ module Fizzy
88
88
  end
89
89
 
90
90
  Response.new(body: parsed_body, headers: response.to_hash, status: status)
91
+ when 400
92
+ raise BadRequestError.new(parse_error(response), status: 400, body: parsed_body)
91
93
  when 301, 302
92
94
  raise AuthError.new("Redirected to #{response["location"]} — endpoint may require session auth",
93
95
  status: status, body: parsed_body)
data/lib/fizzy/errors.rb CHANGED
@@ -11,6 +11,7 @@ module Fizzy
11
11
  end
12
12
  end
13
13
 
14
+ class BadRequestError < Error; end
14
15
  class AuthError < Error; end
15
16
  class NotFoundError < Error; end
16
17
  class ValidationError < Error; end
@@ -20,6 +20,8 @@ module Fizzy
20
20
 
21
21
  def board = @data["board"]
22
22
 
23
+ def boards = @data["boards"] || {}
24
+
23
25
  private
24
26
 
25
27
  def find_config(dir)
data/lib/fizzy/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fizzy
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fizzy-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Paluy