summaryrefslogtreecommitdiff
path: root/scripts/lint-docs-blueprints.rb
blob: 35e0013cb346e9ce06ab5fb5eb6a490d0408240f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env ruby

# frozen_string_literal: true

# Taken from Jekyll
# https://github.com/jekyll/jekyll/blob/3.5-stable/lib/jekyll/document.rb#L13
YAML_FRONT_MATTER_REGEXP = /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m.freeze
READ_LIMIT_BYTES = 1024

require 'yaml'

def extract_front_matter(path)
  File.open(path, 'r') do |f|
    data = if match = YAML_FRONT_MATTER_REGEXP.match(f.read(READ_LIMIT_BYTES))
             YAML.safe_load(match[1])
           else
             {}
           end

    BlueprintFrontMatter.new(data)
  end
end

class BlueprintFrontMatter
  STATUSES = %w[proposed accepted ongoing implemented rejected]

  attr_reader :errors

  def initialize(metadata)
    @metadata = metadata
    @errors = []
  end

  def validate
    validate_status
    validate_authors
    validate_creation_date
  end

  private

  def validate_status
    status = @metadata['status']

    add_error('Missing status') unless status

    return if STATUSES.include?(status)

    add_error("Unsupported status '#{status}': expected one of '#{STATUSES.join(', ')}'")
  end

  def validate_authors
    authors = @metadata['authors']

    add_error('Missing authors') unless authors
    add_error('Authors must be an array') unless authors.is_a?(Array)
  end

  def validate_creation_date
    return if @metadata['creation-date'] =~ /\d{4}-[01]\d-[0123]\d/

    add_error("Invalid creation-date: the date format must be 'yyyy-mm-dd'")
  end

  def add_error(msg)
    @errors << msg
  end
end

if $PROGRAM_NAME == __FILE__
  exit_code = 0

  Dir['doc/architecture/blueprints/*/index.md'].each do |blueprint|
    meta = extract_front_matter(blueprint)
    meta.validate

    next if meta.errors.empty?

    exit_code = 1

    puts("✖ ERROR: Invalid #{blueprint}:")
    meta.errors.each { |e| puts(" - #{e}") }
  end

  exit(exit_code)
end