os-backlog: align .cc-os/config with os-status key=value contract (refs #14)
Config parsed/wrote YAML while os-status owns the file as key=value lines, so config-write output was invisible to the tracker-configured check. Now reads key=value (legacy 'key: value' lines still accepted) and merge emits key=value. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EUyiRB4vHaRkhYKUdoMW2P
This commit is contained in:
parent
696aefcf23
commit
3b9c4fbd88
|
|
@ -1,15 +1,26 @@
|
||||||
require "yaml"
|
|
||||||
|
|
||||||
module Backlog
|
module Backlog
|
||||||
# The parsed contents of a repo's `.cc-os/config` (YAML). Only the
|
# The parsed contents of a repo's `.cc-os/config`. The file format is
|
||||||
# `board` key matters to the resolver: an explicit board-name override.
|
# '#'-commented key=value lines — the contract is owned by os-status
|
||||||
|
# (plugins/os-status/hooks/state.py); legacy `key: value` YAML lines
|
||||||
|
# from earlier os-backlog versions are still read for compatibility.
|
||||||
# Never touches the filesystem itself — callers read the file and pass
|
# Never touches the filesystem itself — callers read the file and pass
|
||||||
# its contents (or nil, if absent) in.
|
# its contents (or nil, if absent) in.
|
||||||
class Config
|
class Config
|
||||||
def initialize(contents)
|
def initialize(contents)
|
||||||
@data = contents.to_s.strip.empty? ? {} : (YAML.safe_load(contents) || {})
|
|
||||||
rescue Psych::SyntaxError
|
|
||||||
@data = {}
|
@data = {}
|
||||||
|
contents.to_s.each_line do |line|
|
||||||
|
line = line.strip
|
||||||
|
next if line.empty? || line.start_with?("#") || line == "---"
|
||||||
|
|
||||||
|
if line.include?("=")
|
||||||
|
key, value = line.split("=", 2)
|
||||||
|
elsif line.include?(": ")
|
||||||
|
key, value = line.split(": ", 2)
|
||||||
|
else
|
||||||
|
next
|
||||||
|
end
|
||||||
|
@data[key.strip] = value.strip
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [String, nil] the explicit board name override, if configured
|
# @return [String, nil] the explicit board name override, if configured
|
||||||
|
|
@ -28,18 +39,19 @@ module Backlog
|
||||||
# @return [Hash] a copy of the parsed config data
|
# @return [Hash] a copy of the parsed config data
|
||||||
def to_h = @data.dup
|
def to_h = @data.dup
|
||||||
|
|
||||||
# Return new YAML contents with `key` set to `value`, preserving every
|
# Return new key=value contents with `key` set to `value`, preserving
|
||||||
# other key already present in `contents`. Pure — does not touch the
|
# every other key already present in `contents` (legacy YAML-style
|
||||||
|
# lines are rewritten to key=value). Pure — does not touch the
|
||||||
# filesystem; callers read/write the file themselves.
|
# filesystem; callers read/write the file themselves.
|
||||||
#
|
#
|
||||||
# @param contents [String, nil] existing raw `.cc-os/config` contents
|
# @param contents [String, nil] existing raw `.cc-os/config` contents
|
||||||
# @param key [String, Symbol] key to set
|
# @param key [String, Symbol] key to set
|
||||||
# @param value [Object] value to set it to
|
# @param value [Object] value to set it to
|
||||||
# @return [String] the updated YAML contents
|
# @return [String] the updated key=value contents
|
||||||
def self.merge(contents, key, value)
|
def self.merge(contents, key, value)
|
||||||
data = new(contents).to_h
|
data = new(contents).to_h
|
||||||
data[key.to_s] = value
|
data[key.to_s] = value.to_s
|
||||||
YAML.dump(data)
|
data.map { |k, v| "#{k}=#{v}\n" }.join
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -13,39 +13,45 @@ class ConfigTest < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_reads_board_key
|
def test_reads_board_key
|
||||||
config = Backlog::Config.new("board: llf-schema\n")
|
config = Backlog::Config.new("board=llf-schema\n")
|
||||||
assert config.configured?
|
assert config.configured?
|
||||||
assert_equal "llf-schema", config.board
|
assert_equal "llf-schema", config.board
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_malformed_yaml_is_treated_as_unconfigured
|
def test_reads_legacy_yaml_style_board_key
|
||||||
config = Backlog::Config.new("board: [unterminated\n")
|
config = Backlog::Config.new("---\nboard: llf-schema\n")
|
||||||
|
assert config.configured?
|
||||||
|
assert_equal "llf-schema", config.board
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_lines_without_separator_are_ignored
|
||||||
|
config = Backlog::Config.new("# comment\njunk line\n")
|
||||||
refute config.configured?
|
refute config.configured?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_yaml_without_board_key_is_unconfigured
|
def test_contents_without_board_key_is_unconfigured
|
||||||
config = Backlog::Config.new("other: value\n")
|
config = Backlog::Config.new("other=value\n")
|
||||||
refute config.configured?
|
refute config.configured?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_reads_tracker_key
|
def test_reads_tracker_key
|
||||||
config = Backlog::Config.new("tracker: forgejo:jared/cc-os\n")
|
config = Backlog::Config.new("tracker=forgejo:jared/cc-os\n")
|
||||||
assert config.tracker_configured?
|
assert config.tracker_configured?
|
||||||
assert_equal "forgejo:jared/cc-os", config.tracker
|
assert_equal "forgejo:jared/cc-os", config.tracker
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_tracker_unconfigured_when_absent
|
def test_tracker_unconfigured_when_absent
|
||||||
config = Backlog::Config.new("board: llf-schema\n")
|
config = Backlog::Config.new("board=llf-schema\n")
|
||||||
refute config.tracker_configured?
|
refute config.tracker_configured?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_merge_sets_new_key_on_nil_contents
|
def test_merge_sets_new_key_on_nil_contents
|
||||||
updated = Backlog::Config.new(Backlog::Config.merge(nil, "tracker", "forgejo:jared/cc-os"))
|
contents = Backlog::Config.merge(nil, "tracker", "forgejo:jared/cc-os")
|
||||||
assert_equal "forgejo:jared/cc-os", updated.tracker
|
assert_equal "tracker=forgejo:jared/cc-os\n", contents
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_merge_preserves_other_keys
|
def test_merge_preserves_other_keys
|
||||||
existing = "board: llf-schema\nother: kept\n"
|
existing = "board=llf-schema\nother=kept\n"
|
||||||
updated_contents = Backlog::Config.merge(existing, "tracker", "planka:llf-schema")
|
updated_contents = Backlog::Config.merge(existing, "tracker", "planka:llf-schema")
|
||||||
updated = Backlog::Config.new(updated_contents)
|
updated = Backlog::Config.new(updated_contents)
|
||||||
|
|
||||||
|
|
@ -55,7 +61,7 @@ class ConfigTest < Minitest::Test
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_merge_overwrites_existing_value_for_key
|
def test_merge_overwrites_existing_value_for_key
|
||||||
existing = "tracker: repo:old\n"
|
existing = "tracker=repo:old\n"
|
||||||
updated = Backlog::Config.new(Backlog::Config.merge(existing, "tracker", "repo:new"))
|
updated = Backlog::Config.new(Backlog::Config.merge(existing, "tracker", "repo:new"))
|
||||||
assert_equal "repo:new", updated.tracker
|
assert_equal "repo:new", updated.tracker
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue