Module: DocOpsLab::Dev::ConfigManager

Defined in:
lib/docopslab/dev/config_manager.rb

Class Method Summary collapse

Class Method Details

.apply_vale_style_override(content, override_type) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/docopslab/dev/config_manager.rb', line 221

def apply_vale_style_override content, override_type
  # Parse the INI content
  config = parse_simple_ini(content)

  # Apply the override to the [*.adoc] section
  if config['*.adoc']
    case override_type
    when :text
      config['*.adoc']['BasedOnStyles'] = 'RedHat, DocOpsLab-Authoring'
    when :adoc
      config['*.adoc']['BasedOnStyles'] = 'AsciiDoc, DocOpsLab-AsciiDoc'
    end
  end

  # Convert back to INI format
  generate_simple_ini(config)
end

.deep_merge_configs(base, local) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/docopslab/dev/config_manager.rb', line 116

def deep_merge_configs base, local
  return local if base.nil?
  return base if local.nil?

  case local
  when Hash
    result = base.is_a?(Hash) ? base.dup : {}
    local.each do |key, value|
      if value.nil? # YAML null (~) cancels the setting
        result.delete(key)
      else
        result[key] = deep_merge_configs(result[key], value)
      end
    end
    result
  else
    # Non-hash values: local completely overrides base (including arrays)
    local
  end
end

.generate_htmlproofer_config(_context) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/docopslab/dev/config_manager.rb', line 36

def generate_htmlproofer_config _context
  base_config = File.join(CONFIG_VENDOR_DIR, 'htmlproofer.yml')
  project_config = '.config/htmlproofer.local.yml'
  generated_config = CONFIG_PATHS[:htmlproofer]

  return false unless File.exist?(base_config)

  merged_content = if File.exist?(project_config)
                     merge_yaml_configs(base_config, project_config)
                   else
                     File.read(base_config)
                   end

  if !File.exist?(generated_config) || File.read(generated_config) != merged_content
    File.write(generated_config, merged_content)
    puts "  📝 Generated #{generated_config} from base#{' + local' if File.exist?(project_config)}"
    true
  else
    false
  end
end

.generate_simple_ini(config) ⇒ Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/docopslab/dev/config_manager.rb', line 137

def generate_simple_ini config
  lines = []

  # Global section first
  if config['global'] && !config['global'].empty?
    config['global'].each do |key, value|
      lines << "#{key} = #{value}"
    end
    lines << ''
  end

  # Other sections
  config.each do |section_name, section_data|
    next if section_name == 'global'
    next if section_data.empty?

    lines << "[#{section_name}]"
    section_data.each do |key, value|
      lines << "#{key} = #{value}"
    end
    lines << ''
  end

  "#{lines.join("\n").strip}\n"
end

.generate_vale_config(_context, style_override: nil) ⇒ Object



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
# File 'lib/docopslab/dev/config_manager.rb', line 7

def generate_vale_config _context, style_override: nil
  base_config = File.join(CONFIG_VENDOR_DIR, 'vale.ini')
  project_config = '.config/vale.local.ini'
  generated_config = CONFIG_PATHS[:vale]

  return false unless File.exist?(base_config)

  merged_content = if File.exist?(project_config)
                     merge_ini_configs(base_config, project_config)
                   else
                     File.read(base_config)
                   end

  # Apply runtime style override if specified
  merged_content = apply_vale_style_override(merged_content, style_override) if style_override

  # Write generated config
  if !File.exist?(generated_config) || File.read(generated_config) != merged_content
    File.write(generated_config, merged_content)
    override_msg = style_override ? " (#{style_override} styles)" : ''
    puts "  📝 Generated #{generated_config} from base#{if File.exist?(project_config)
                                                         ' + local'
                                                       end}#{override_msg}"
    true
  else
    false
  end
end

.get_path_config(tool_slug, context) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/docopslab/dev/config_manager.rb', line 163

def get_path_config tool_slug, context
  tool_meta = context.(tool_slug)
  default_config = tool_meta&.dig('paths') || {}

  manifest = context.load_manifest
  project_config = manifest&.dig('tools')&.find { |t| t['tool'] == tool_slug }&.dig('paths') || {}

  git_tracked_only = if project_config.key?('git_tracked_only')
                       project_config['git_tracked_only']
                     else
                       default_config.fetch('git_tracked_only', true)
                     end

  # Project-level 'lint'/'skip' overrides gem-level 'patterns'/'ignored_paths'
  lint_paths = project_config['lint'] || default_config['patterns']
  skip_paths = (project_config['skip'] || []) + (default_config['ignored_paths'] || [])

  {
    lint: lint_paths,
    skip: skip_paths.uniq,
    exts: project_config['exts'] || default_config['exts'],
    git_tracked_only: git_tracked_only
  }
end

.load_htmlproofer_config(config_path = nil, policy: 'merge') ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/docopslab/dev/config_manager.rb', line 58

def load_htmlproofer_config config_path=nil, policy: 'merge'
  config_paths = if config_path && File.exist?(config_path)
                   [config_path]
                 else
                   [CONFIG_PATHS[:htmlproofer]]
                 end
  config_paths << File.join(CONFIG_VENDOR_DIR, 'htmlproofer.yml') unless policy == 'replace'
  config_path = config_paths.find { |path| File.exist?(path) }

  return unless config_path

  puts "📋 Using HTMLProofer config: #{config_path}"
  begin
    config = YAML.load_file(config_path)
    # Convert string patterns to regex for ignore_urls and ignore_files
    process_htmlproofer_patterns(config)
  rescue StandardError => e
    puts "⚠️  Failed to load #{config_path}: #{e.message}"
  end
end

.merge_ini_configs(base_path, local_path) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
# File 'lib/docopslab/dev/config_manager.rb', line 188

def merge_ini_configs base_path, local_path
  # Simple but working INI merger; good enough for our needs
  base_config = parse_simple_ini(File.read(base_path))
  project_config = parse_simple_ini(File.read(local_path))

  # Merge with RuboCop semantics: local overrides base, sections merge
  merged_config = deep_merge_configs(base_config, project_config)

  # Convert back to INI format
  generate_simple_ini(merged_config)
end

.merge_yaml_configs(base_path, local_path) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/docopslab/dev/config_manager.rb', line 102

def merge_yaml_configs base_path, local_path
  # Implement RuboCop-style inheritance for YAML files
  require 'yaml'

  base_config = YAML.load_file(base_path) || {}
  project_config = YAML.load_file(local_path) || {}

  # Merge with RuboCop semantics
  merged_config = deep_merge_configs(base_config, project_config)

  # Convert back to YAML
  YAML.dump(merged_config)
end

.parse_simple_ini(content) ⇒ Object



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/docopslab/dev/config_manager.rb', line 200

def parse_simple_ini content
  config = { 'global' => {} }
  current_section = 'global'

  content.lines.each do |line|
    line = line.strip
    next if line.empty? || line.start_with?('#')

    if line =~ /^\[(.+)\]$/
      current_section = ::Regexp.last_match(1)
      config[current_section] = {}
    elsif line =~ /^([^=]+)\s*=\s*(.*)$/
      key = ::Regexp.last_match(1).strip
      value = ::Regexp.last_match(2).strip
      config[current_section][key] = value
    end
  end

  config
end

.process_htmlproofer_patterns(config) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/docopslab/dev/config_manager.rb', line 79

def process_htmlproofer_patterns config
  # Convert string patterns to regex for ignore_urls
  if config['ignore_urls'].is_a?(Array)
    config['ignore_urls'] = config['ignore_urls'].map do |pattern|
      if pattern.is_a?(String) && pattern.start_with?('/') && pattern.end_with?('/')
        Regexp.new(pattern[1..-2])
      else
        pattern
      end
    end
  end

  # Convert string patterns to regex for ignore_files
  if config['ignore_files'].is_a?(Array)
    config['ignore_files'] = config['ignore_files'].map do |pattern|
      pattern.is_a?(String) ? Regexp.new(pattern) : pattern
    end
  end

  # Convert string keys to symbols for HTMLProofer
  config.transform_keys(&:to_sym)
end