Revision 7d4f91f0
Added by Oleksandr Ivanov 1 day ago
| lib/almirah/doc_types/decision.rb | ||
|---|---|---|
|
require_relative 'base_document'
|
||
|
|
||
|
class Decision < BaseDocument # rubocop:disable Style/Documentation
|
||
|
attr_accessor :path
|
||
|
attr_accessor :path, :sequence_number, :record_type
|
||
|
|
||
|
def initialize(file_path)
|
||
|
super()
|
||
|
@path = file_path
|
||
|
@id = File.basename(file_path, File.extname(file_path)).downcase
|
||
|
@title = extract_title(file_path) || @id
|
||
|
stem = File.basename(file_path, File.extname(file_path))
|
||
|
assign_id_parts(stem)
|
||
|
@title = extract_title(file_path) || stem
|
||
|
end
|
||
|
|
||
|
def to_console
|
||
| ... | ... | |
|
|
||
|
private
|
||
|
|
||
|
def assign_id_parts(stem)
|
||
|
match = stem.match(/\A([A-Za-z]+)-(\d+)/)
|
||
|
if match
|
||
|
@id = "#{match[1]}-#{match[2]}".downcase
|
||
|
@record_type = match[1].upcase
|
||
|
@sequence_number = match[2]
|
||
|
else
|
||
|
@id = stem.downcase
|
||
|
@record_type = nil
|
||
|
@sequence_number = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def extract_title(file_path)
|
||
|
File.foreach(file_path) do |line|
|
||
|
if (match = /^\#\s+(.+)$/.match(line))
|
||
| lib/almirah/doc_types/decisions_overview.rb | ||
|---|---|---|
|
|
||
|
html_rows.append "<table class=\"controlled\">\n"
|
||
|
html_rows.append "\t<thead>\n"
|
||
|
html_rows.append "\t\t<th>ID</th>\n"
|
||
|
html_rows.append "\t\t<th>#</th>\n"
|
||
|
html_rows.append "\t\t<th>Type</th>\n"
|
||
|
html_rows.append "\t\t<th>Title</th>\n"
|
||
|
html_rows.append "</thead>\n"
|
||
|
|
||
|
sorted_items = @project.project_data.decisions.sort_by(&:id)
|
||
|
sorted_items.each do |doc|
|
||
|
s = "\t<tr>\n"
|
||
|
s += "\t\t<td class=\"item_id\" style='width: 20%;'>#{doc.id}</td>\n"
|
||
|
s += "\t\t<td class=\"item_id\">\n"
|
||
|
label = doc.sequence_number || doc.id
|
||
|
anchor_attrs = %(name="#{doc.id}" id="#{doc.id}" href="##{doc.id}" title="Decision Record ID")
|
||
|
s += "\t\t\t<a #{anchor_attrs}><b>#{label}</b></a>"
|
||
|
s += "\t\t</td>\n"
|
||
|
s += "\t\t<td class=\"item_type\">#{doc.record_type}</td>\n"
|
||
|
s += "\t\t<td class=\"item_text\" style='padding: 5px;'>#{doc.title}</td>\n"
|
||
|
s += "</tr>\n"
|
||
|
html_rows.append s
|
||
| lib/almirah/templates/css/main.css | ||
|---|---|---|
|
width: 3%;
|
||
|
text-align: center;
|
||
|
}
|
||
|
table.controlled td.item_type {
|
||
|
width: 5%;
|
||
|
text-align: center;
|
||
|
font-weight: normal;
|
||
|
}
|
||
|
table.controlled td.item_text{
|
||
|
text-align: left;
|
||
|
}
|
||
| spec/e2e/decisions_spec.rb | ||
|---|---|---|
|
|
||
|
it 'lists all parsed decision records on the overview page' do
|
||
|
doc = Nokogiri::HTML(File.read(expand_path('myproject/build/decisions/overview.html')))
|
||
|
ids = doc.xpath('//td[@class="item_id"]').map { |c| c.text.strip }
|
||
|
sequence_numbers = doc.xpath('//td[@class="item_id"]').map { |c| c.text.strip }
|
||
|
anchor_ids = doc.xpath('//td[@class="item_id"]//a').map { |a| a['id'] }
|
||
|
types = doc.xpath('//td[@class="item_type"]').map { |c| c.text.strip }
|
||
|
titles = doc.xpath('//td[@class="item_text"]').map { |c| c.text.strip }
|
||
|
expect(ids).to contain_exactly('adr-001-foo', 'adr-002-bar')
|
||
|
expect(sequence_numbers).to contain_exactly('001', '002')
|
||
|
expect(anchor_ids).to contain_exactly('adr-001', 'adr-002')
|
||
|
expect(types).to contain_exactly('ADR', 'ADR')
|
||
|
expect(titles).to contain_exactly('ADR-001: First Decision', 'ADR-002: Second Decision')
|
||
|
end
|
||
|
|
||
| ... | ... | |
|
specifications:
|
||
|
input: []
|
||
|
YML
|
||
|
write_file('myproject/specifications/req/req.md', "# Requirements\n\n[REQ-001] x\n")
|
||
|
write_file('myproject/decisions/adr-001-titleless.md', "body without heading\n")
|
||
|
run_command_and_stop('almirah please myproject')
|
||
|
end
|
||
|
|
||
|
it 'falls back to the filename-derived id for the title' do
|
||
|
it 'derives the id from the letters-digits prefix and falls back to the full stem for the title' do
|
||
|
doc = Nokogiri::HTML(File.read(expand_path('myproject/build/decisions/overview.html')))
|
||
|
sequence_numbers = doc.xpath('//td[@class="item_id"]').map { |c| c.text.strip }
|
||
|
anchor_ids = doc.xpath('//td[@class="item_id"]//a').map { |a| a['id'] }
|
||
|
types = doc.xpath('//td[@class="item_type"]').map { |c| c.text.strip }
|
||
|
titles = doc.xpath('//td[@class="item_text"]').map { |c| c.text.strip }
|
||
|
expect(sequence_numbers).to eq(['001'])
|
||
|
expect(anchor_ids).to eq(['adr-001'])
|
||
|
expect(types).to eq(['ADR'])
|
||
|
expect(titles).to eq(['adr-001-titleless'])
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when a decision record filename has no descriptive suffix' do
|
||
|
before do
|
||
|
write_file('myproject/project.yml', <<~YML)
|
||
|
specifications:
|
||
|
input: []
|
||
|
YML
|
||
|
write_file('myproject/decisions/ise-1892.md', <<~MD)
|
||
|
# ISE-1892: A redmine-style record
|
||
|
|
||
|
body
|
||
|
MD
|
||
|
run_command_and_stop('almirah please myproject')
|
||
|
end
|
||
|
|
||
|
it 'uses the full letters-digits stem as the id and shows the digits in the # column' do
|
||
|
doc = Nokogiri::HTML(File.read(expand_path('myproject/build/decisions/overview.html')))
|
||
|
sequence_numbers = doc.xpath('//td[@class="item_id"]').map { |c| c.text.strip }
|
||
|
anchor_ids = doc.xpath('//td[@class="item_id"]//a').map { |a| a['id'] }
|
||
|
types = doc.xpath('//td[@class="item_type"]').map { |c| c.text.strip }
|
||
|
titles = doc.xpath('//td[@class="item_text"]').map { |c| c.text.strip }
|
||
|
expect(sequence_numbers).to eq(['1892'])
|
||
|
expect(anchor_ids).to eq(['ise-1892'])
|
||
|
expect(types).to eq(['ISE'])
|
||
|
expect(titles).to eq(['ISE-1892: A redmine-style record'])
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when a decision record filename does not match the convention' do
|
||
|
before do
|
||
|
write_file('myproject/project.yml', <<~YML)
|
||
|
specifications:
|
||
|
input: []
|
||
|
YML
|
||
|
write_file('myproject/decisions/meeting-notes.md', <<~MD)
|
||
|
# Meeting notes
|
||
|
|
||
|
body
|
||
|
MD
|
||
|
run_command_and_stop('almirah please myproject')
|
||
|
end
|
||
|
|
||
|
it 'falls back to the full filename stem as the id and as the # column label, with empty Type' do
|
||
|
doc = Nokogiri::HTML(File.read(expand_path('myproject/build/decisions/overview.html')))
|
||
|
sequence_numbers = doc.xpath('//td[@class="item_id"]').map { |c| c.text.strip }
|
||
|
anchor_ids = doc.xpath('//td[@class="item_id"]//a').map { |a| a['id'] }
|
||
|
types = doc.xpath('//td[@class="item_type"]').map { |c| c.text.strip }
|
||
|
expect(sequence_numbers).to eq(['meeting-notes'])
|
||
|
expect(anchor_ids).to eq(['meeting-notes'])
|
||
|
expect(types).to eq([''])
|
||
|
end
|
||
|
end
|
||
|
|
||
|
context 'when the project has no decision records' do
|
||
|
before do
|
||
|
write_file('myproject/project.yml', <<~YML)
|
||
Also available in: Unified diff
Impl: Decision record id and type are added to the overview table (#170)