module Adr # The docs/adr/ directory of one project. Scans files, derives the next ID # from directory contents (never the index), reads and writes records. class Repository INDEX_FILENAME = "README.md" Entry = Struct.new(:path, :record) def initialize(root:) @root = root end attr_reader :root def dir = File.join(root, "docs", "adr") def index_path = File.join(dir, INDEX_FILENAME) def exists? Dir.exist?(dir) && File.exist?(index_path) end def adr_paths Dir.glob(File.join(dir, "[0-9][0-9][0-9][0-9]-*.md")).sort end # Only files in the os-adr format count as entries; legacy frontmatter-less # files sharing docs/adr/ (pre-migration sources) are skipped, not errors. def entries adr_paths.filter_map do |path| Entry.new(path, Record.parse(File.read(path))) rescue Record::ParseError, Psych::SyntaxError nil end end def next_id max = adr_paths.map { |path| File.basename(path)[0, 4].to_i }.max || 0 format("%04d", max + 1) end def find(id) entries.find { |entry| entry.record.id == id } end def write(record) path = File.join(dir, "#{record.id}-#{Adr.slugify(record.title)}.md") File.write(path, record.to_markdown) path end def write_entry(entry) File.write(entry.path, entry.record.to_markdown) end end end