fizzy-cli 0.4.1 → 0.6.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 +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +24 -3
- data/lib/fizzy/cli/auth.rb +12 -7
- data/lib/fizzy/cli/base.rb +6 -1
- data/lib/fizzy/cli/boards.rb +15 -0
- data/lib/fizzy/cli.rb +11 -8
- data/lib/fizzy/client.rb +9 -5
- data/lib/fizzy/project_config.rb +4 -0
- data/lib/fizzy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1684a8ac9b61399c368c8ff3b5828f00f965d65cfedadaa03c23eefe002f4661
|
|
4
|
+
data.tar.gz: 31615887c4f1c5bbdc7b33c08e216690a1b440b8551e8328ecbefcb455e2fbe4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 262b4e467ca32aaa6e202bb21358d0111870ca449983112abdd0d45cfe8e87229b904f0b28185c7ab4246848f69222d9e363aadae9bb49a25af4314a4e96bc5e
|
|
7
|
+
data.tar.gz: c6d180d3c263bbf9eefe2bcdd28de99809d825d8af974044e64a8d91c66ac45d7cd35ef07e5dad3204b59187fa6e1c62d4aed303655585ffe5693cd20b95268c
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ 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.6.0] - 2026-02-23
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Custom URL support for self-hosted Fizzy instances
|
|
12
|
+
- `fizzy auth login --url URL` stores instance URL per-account in tokens.yml
|
|
13
|
+
- `url` key in `.fizzy.yml` for per-project instance URL
|
|
14
|
+
- `FIZZY_URL` environment variable for instance URL override
|
|
15
|
+
- URL resolution priority: `FIZZY_URL` env > `.fizzy.yml` > tokens.yml per-account > default
|
|
16
|
+
- URL validation in Client rejects non-http(s) URLs with clear error message
|
|
17
|
+
- `auth status` displays URL when using a non-default instance
|
|
18
|
+
- HTTP scheme detection for SSL (supports `http://` for local development)
|
|
19
|
+
|
|
20
|
+
## [0.5.0] - 2026-02-22
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- Cache boards in `.fizzy.yml` as `boards: { id: name }` hash for quick lookups without API calls
|
|
24
|
+
- `fizzy boards sync` command to refresh the cached boards list from the API
|
|
25
|
+
- `fizzy init` now automatically fetches and caches all boards during setup
|
|
26
|
+
- `ProjectConfig#boards` accessor for reading cached board data
|
|
27
|
+
|
|
8
28
|
## [0.4.1] - 2026-02-22
|
|
9
29
|
|
|
10
30
|
### Fixed
|
data/README.md
CHANGED
|
@@ -43,7 +43,13 @@ fizzy skill uninstall # Remove skill file
|
|
|
43
43
|
fizzy auth login --token YOUR_TOKEN
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
For self-hosted Fizzy instances, pass `--url`:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
fizzy auth login --token YOUR_TOKEN --url https://fizzy.mycompany.com
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The URL is stored per-account in `~/.config/fizzy-cli/tokens.yml`. You can also set `FIZZY_TOKEN` as an environment variable with `--account` to skip the file.
|
|
47
53
|
|
|
48
54
|
```sh
|
|
49
55
|
fizzy auth status # Show current auth
|
|
@@ -66,6 +72,14 @@ account: acme
|
|
|
66
72
|
board: b1
|
|
67
73
|
```
|
|
68
74
|
|
|
75
|
+
For self-hosted instances, add a `url` key:
|
|
76
|
+
|
|
77
|
+
```yaml
|
|
78
|
+
account: acme
|
|
79
|
+
board: b1
|
|
80
|
+
url: https://fizzy.mycompany.com
|
|
81
|
+
```
|
|
82
|
+
|
|
69
83
|
**Resolution priority** (highest wins):
|
|
70
84
|
1. CLI flag (`--account` / `--board`)
|
|
71
85
|
2. `.fizzy.yml` (nearest ancestor directory)
|
|
@@ -210,9 +224,16 @@ end
|
|
|
210
224
|
|
|
211
225
|
| Source | Purpose |
|
|
212
226
|
|--------|---------|
|
|
213
|
-
| `.fizzy.yml` | Per-project account and
|
|
214
|
-
| `~/.config/fizzy-cli/tokens.yml` | Stored auth tokens
|
|
227
|
+
| `.fizzy.yml` | Per-project account, board, and URL defaults |
|
|
228
|
+
| `~/.config/fizzy-cli/tokens.yml` | Stored auth tokens, default account, and per-account URL |
|
|
215
229
|
| `FIZZY_TOKEN` env var | Token override (requires `--account`) |
|
|
230
|
+
| `FIZZY_URL` env var | Instance URL override (default: `https://app.fizzy.do`) |
|
|
231
|
+
|
|
232
|
+
**URL resolution priority** (highest wins):
|
|
233
|
+
1. `FIZZY_URL` environment variable
|
|
234
|
+
2. `url` in `.fizzy.yml`
|
|
235
|
+
3. Per-account `url` from `tokens.yml` (set via `fizzy auth login --url`)
|
|
236
|
+
4. Default: `https://app.fizzy.do`
|
|
216
237
|
|
|
217
238
|
## Development
|
|
218
239
|
|
data/lib/fizzy/cli/auth.rb
CHANGED
|
@@ -24,11 +24,15 @@ module Fizzy
|
|
|
24
24
|
|
|
25
25
|
desc "login", "Authenticate with a Personal Access Token"
|
|
26
26
|
option :token, required: true, desc: "Personal Access Token"
|
|
27
|
+
option :url, type: :string, desc: "Custom Fizzy instance URL (default: #{Client::DEFAULT_BASE_URL})"
|
|
27
28
|
def login
|
|
28
29
|
token = options[:token]
|
|
30
|
+
custom_url = options[:url]
|
|
29
31
|
|
|
30
32
|
# Verify token by fetching identity
|
|
31
|
-
|
|
33
|
+
client_opts = { token: token, account_slug: "" }
|
|
34
|
+
client_opts[:base_url] = custom_url if custom_url
|
|
35
|
+
c = Client.new(**client_opts)
|
|
32
36
|
resp = c.get("/my/identity")
|
|
33
37
|
accounts = resp.body["accounts"]
|
|
34
38
|
|
|
@@ -36,7 +40,7 @@ module Fizzy
|
|
|
36
40
|
|
|
37
41
|
# Build tokens data
|
|
38
42
|
token_accounts = accounts.map do |a|
|
|
39
|
-
{
|
|
43
|
+
acct = {
|
|
40
44
|
"account_slug" => Auth.normalize_slug(a["slug"]),
|
|
41
45
|
"account_name" => a["name"],
|
|
42
46
|
"account_id" => a["id"],
|
|
@@ -49,6 +53,8 @@ module Fizzy
|
|
|
49
53
|
},
|
|
50
54
|
"created_at" => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.%3NZ")
|
|
51
55
|
}
|
|
56
|
+
acct["url"] = custom_url if custom_url
|
|
57
|
+
acct
|
|
52
58
|
end
|
|
53
59
|
|
|
54
60
|
data = {
|
|
@@ -69,13 +75,12 @@ module Fizzy
|
|
|
69
75
|
|
|
70
76
|
desc "status", "Show current auth status"
|
|
71
77
|
def status
|
|
72
|
-
|
|
73
|
-
c = Client.new(token: acct["access_token"], account_slug: acct["account_slug"])
|
|
74
|
-
resp = c.get("/my/identity")
|
|
78
|
+
resp = client.get("/my/identity")
|
|
75
79
|
|
|
80
|
+
puts "URL: #{client.base_url}" unless base_url == Client::DEFAULT_BASE_URL
|
|
76
81
|
puts "Token: #{Auth::TOKEN_FILE}"
|
|
77
|
-
puts "Account: #{
|
|
78
|
-
puts "User: #{
|
|
82
|
+
puts "Account: #{account["account_name"]} (#{account["account_slug"]})"
|
|
83
|
+
puts "User: #{account.dig("user", "name")} <#{account.dig("user", "email_address")}>"
|
|
79
84
|
|
|
80
85
|
accounts_count = resp.body["accounts"].size
|
|
81
86
|
puts "Accounts: #{accounts_count}" if accounts_count > 1
|
data/lib/fizzy/cli/base.rb
CHANGED
|
@@ -37,10 +37,15 @@ module Fizzy
|
|
|
37
37
|
"No value provided for option '--board'. Set via --board, .fizzy.yml, or: fizzy init")
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
def base_url
|
|
41
|
+
ENV["FIZZY_URL"] || project_config.url || account["url"] || Client::DEFAULT_BASE_URL
|
|
42
|
+
end
|
|
43
|
+
|
|
40
44
|
def client
|
|
41
45
|
@client ||= Client.new(
|
|
42
46
|
token: account["access_token"],
|
|
43
|
-
account_slug: account["account_slug"]
|
|
47
|
+
account_slug: account["account_slug"],
|
|
48
|
+
base_url: base_url
|
|
44
49
|
)
|
|
45
50
|
end
|
|
46
51
|
|
data/lib/fizzy/cli/boards.rb
CHANGED
|
@@ -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
|
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
|
-
|
|
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,15 @@ module Fizzy
|
|
|
97
100
|
accounts[idx]
|
|
98
101
|
end
|
|
99
102
|
|
|
100
|
-
def
|
|
101
|
-
|
|
103
|
+
def fetch_boards(account)
|
|
104
|
+
url = ENV["FIZZY_URL"] || account["url"] || Client::DEFAULT_BASE_URL
|
|
105
|
+
c = Client.new(token: account["access_token"], account_slug: account["account_slug"], base_url: url)
|
|
102
106
|
boards = c.get("boards").body
|
|
107
|
+
say "No boards found." if boards.empty?
|
|
108
|
+
boards
|
|
109
|
+
end
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
say "No boards found."
|
|
106
|
-
return nil
|
|
107
|
-
end
|
|
108
|
-
|
|
111
|
+
def pick_board(boards)
|
|
109
112
|
say "Boards:"
|
|
110
113
|
boards.each_with_index do |b, i|
|
|
111
114
|
say " #{i + 1}. #{b["name"]} (#{b["id"]})"
|
data/lib/fizzy/client.rb
CHANGED
|
@@ -4,11 +4,15 @@ module Fizzy
|
|
|
4
4
|
Response = Data.define(:body, :headers, :status)
|
|
5
5
|
|
|
6
6
|
class Client
|
|
7
|
-
|
|
7
|
+
DEFAULT_BASE_URL = "https://app.fizzy.do"
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
attr_reader :base_url
|
|
10
|
+
|
|
11
|
+
def initialize(token:, account_slug:, base_url: DEFAULT_BASE_URL)
|
|
10
12
|
@token = token
|
|
11
13
|
@account_slug = account_slug
|
|
14
|
+
@base_url = base_url.chomp("/")
|
|
15
|
+
raise ArgumentError, "Invalid URL (must be http or https): #{@base_url}" unless @base_url.match?(%r{\Ahttps?://})
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
def get(path, params: {})
|
|
@@ -31,9 +35,9 @@ module Fizzy
|
|
|
31
35
|
|
|
32
36
|
def connection
|
|
33
37
|
@connection ||= begin
|
|
34
|
-
uri = URI(
|
|
38
|
+
uri = URI(@base_url)
|
|
35
39
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
36
|
-
http.use_ssl =
|
|
40
|
+
http.use_ssl = uri.scheme == "https"
|
|
37
41
|
http.open_timeout = 5
|
|
38
42
|
http.read_timeout = 30
|
|
39
43
|
http.start
|
|
@@ -48,7 +52,7 @@ module Fizzy
|
|
|
48
52
|
|
|
49
53
|
def request(method, path, body: nil, params: {})
|
|
50
54
|
full_path = path.start_with?("/") ? path : "/#{@account_slug}/#{path}"
|
|
51
|
-
uri = URI("#{
|
|
55
|
+
uri = URI("#{@base_url}#{full_path}")
|
|
52
56
|
uri.query = URI.encode_www_form(params) unless params.empty?
|
|
53
57
|
|
|
54
58
|
req = build_request(method, uri)
|
data/lib/fizzy/project_config.rb
CHANGED
data/lib/fizzy/version.rb
CHANGED