|
| 1 | +lib = File.expand_path('lib', __dir__) |
| 2 | +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) |
| 3 | +require 'datadog' |
| 4 | + |
| 5 | +require 'yaml' |
| 6 | + |
| 7 | +regenerate_todo = ARGV.include?('--regenerate-todo') |
| 8 | +ignore_todo = ARGV.include?('--ignore-todo') |
| 9 | + |
| 10 | +DOCS = File.read('docs/GettingStarted.md') |
| 11 | + |
| 12 | +todos = if !regenerate_todo && !ignore_todo && File.exist?('.github/check_config_doc_todo.yml') |
| 13 | + YAML.safe_load(File.read('.github/check_config_doc_todo.yml')) |
| 14 | + else |
| 15 | + { |
| 16 | + 'library' => [], |
| 17 | + 'integrations' => Hash.new { |h, k| h[k] = [] } |
| 18 | + } |
| 19 | + end |
| 20 | + |
| 21 | +total_todos = 0 |
| 22 | +total_oks = 0 |
| 23 | + |
| 24 | +def walk(config, path = nil, &block) |
| 25 | + config.to_h.each do |key, value| |
| 26 | + if value.is_a?(Datadog::Core::Configuration::Base) |
| 27 | + walk(value, "#{path}#{key}.", &block) |
| 28 | + else |
| 29 | + block.call("#{path}#{key}") |
| 30 | + end |
| 31 | + end |
| 32 | +end |
| 33 | + |
| 34 | +library_offences = [] |
| 35 | + |
| 36 | +walk(Datadog.configuration) do |full_name| |
| 37 | + if !DOCS.include?(full_name) |
| 38 | + total_todos += 1 |
| 39 | + if regenerate_todo || !todos['library']&.include?(full_name) |
| 40 | + library_offences << full_name |
| 41 | + end |
| 42 | + else |
| 43 | + total_oks += 1 |
| 44 | + end |
| 45 | +end |
| 46 | + |
| 47 | +integration_offences = Hash.new { |h, k| h[k] = [] } |
| 48 | + |
| 49 | +Datadog::Tracing::Contrib::REGISTRY.to_h.each do |integration_name, _| |
| 50 | + config = Datadog.configuration.tracing[integration_name] |
| 51 | + walk(config) do |full_name| |
| 52 | + # Convert `_` in the integration name to any character or no character, as we have |
| 53 | + # different cases, e.g. DelayedJob, Action Cable. |
| 54 | + name_match = integration_name.to_s.gsub('_', '.?') |
| 55 | + |
| 56 | + matcher = Regexp.new('^### ' + name_match + '\s*\n(.*?)(?=^### |\z)', Regexp::IGNORECASE | Regexp::MULTILINE) |
| 57 | + |
| 58 | + section = DOCS[matcher, 1] |
| 59 | + if section |
| 60 | + if !section.include?(full_name) |
| 61 | + total_todos += 1 |
| 62 | + if regenerate_todo || !todos['integrations'][integration_name.to_s]&.include?(full_name) |
| 63 | + integration_offences[integration_name.to_s] << full_name |
| 64 | + end |
| 65 | + else |
| 66 | + total_oks += 1 |
| 67 | + end |
| 68 | + else |
| 69 | + total_todos += 1 |
| 70 | + if regenerate_todo || !todos['integrations'][integration_name.to_s]&.include?('all') |
| 71 | + integration_offences[integration_name.to_s] = 'all' |
| 72 | + end |
| 73 | + end |
| 74 | + end |
| 75 | +end |
| 76 | + |
| 77 | +integration_offences_count = integration_offences.values.flatten.size |
| 78 | +total_offences = library_offences.size + integration_offences_count |
| 79 | + |
| 80 | +def green(str) |
| 81 | + "\e[32m#{str}\e[0m" |
| 82 | +end |
| 83 | + |
| 84 | +def yellow(str) |
| 85 | + "\e[33m#{str}\e[0m" |
| 86 | +end |
| 87 | + |
| 88 | +def print_library_offence_details(offences, search_dir, exclude_dir = '') |
| 89 | + offences.each do |offence| |
| 90 | + STDERR.puts " • #{offence}" |
| 91 | + search_term = "option :#{offence.split('.')[-1]}" |
| 92 | + matches = `grep -nE --exclude-dir=#{exclude_dir} '^[^#]*#{search_term}' -R #{search_dir}` |
| 93 | + lines = matches.lines |
| 94 | + if lines.size == 1 |
| 95 | + STDERR.puts " #{lines[0].strip}" |
| 96 | + elsif lines.size > 1 |
| 97 | + STDERR.puts " Found in multiple places:" |
| 98 | + lines.each do |line| |
| 99 | + STDERR.puts " #{line.strip}" |
| 100 | + end |
| 101 | + end |
| 102 | + end |
| 103 | +end |
| 104 | + |
| 105 | +puts green("😁 Total options documented: #{total_oks}") if total_oks > 0 |
| 106 | + |
| 107 | +puts yellow("🧐 Total offences ignored by TODOs: #{total_todos}") if !ignore_todo && !regenerate_todo && total_todos > 0 |
| 108 | + |
| 109 | +if regenerate_todo |
| 110 | + todos = { |
| 111 | + 'library' => library_offences, |
| 112 | + 'integrations' => integration_offences |
| 113 | + } |
| 114 | + File.write('.github/check_config_doc_todo.yml', todos.to_yaml) |
| 115 | + puts green("✒️ #{total_offences} total TODOs updated in .github/check_config_doc_todo.yml") |
| 116 | +elsif total_offences > 0 |
| 117 | + if library_offences.size > 0 |
| 118 | + STDERR.puts "❗️Library configuration options not documented: #{library_offences.size}" |
| 119 | + print_library_offence_details(library_offences, "lib", "lib/datadog/tracing/contrib") |
| 120 | + STDERR.puts |
| 121 | + STDERR.puts " Please document them in docs/GettingStarted.md, section `## Additional configuration`" |
| 122 | + STDERR.puts |
| 123 | + end |
| 124 | + |
| 125 | + if integration_offences_count > 0 |
| 126 | + STDERR.puts "️️️❗️Integration configuration options not documented: #{integration_offences_count}" |
| 127 | + integration_offences.each do |integration, offences| |
| 128 | + if offences == 'all' |
| 129 | + STDERR.puts " ▸ Integration '#{integration}'" |
| 130 | + STDERR.puts " • Documentation section not found!" |
| 131 | + else |
| 132 | + STDERR.puts " ▸ Integration '#{integration}'" |
| 133 | + print_library_offence_details(offences, "lib/datadog/tracing/contrib/#{integration}") |
| 134 | + end |
| 135 | + end |
| 136 | + STDERR.puts |
| 137 | + STDERR.puts " Please document them in docs/GettingStarted.md, section `## Integration instrumentation`" |
| 138 | + end |
| 139 | + |
| 140 | + STDERR.puts |
| 141 | + STDERR.puts "😭 Total offences found: #{total_offences}" |
| 142 | + exit 1 |
| 143 | +end |
| 144 | + |
0 commit comments