Module: CheckFileSyntax

Defined in:
lib/check_file_syntax.rb

Constant Summary collapse

ALL_CHECKS =
[:puppet, :ruby, :python, :perl, :bash, :erb, :yaml, :json]

Class Method Summary collapse

Class Method Details

.bash_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
# File 'lib/check_file_syntax.rb', line 71

def bash_file?(path)
  type_of_file(path, :bash, ['.sh', '.bash', '.zsh', '.ksh'])
end

.check_file_syntax(path, &block) ⇒ Object



133
134
135
136
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/check_file_syntax.rb', line 133

def check_file_syntax(path, &block)
  errors = ''
  status = nil

  if puppet_file? path
    if system('which puppet >/dev/null')
      errors = `puppet parser validate #{path} 2>&1`
      status = $?.success? ? :passed : :failed
    else
      puts 'Consider installing puppet so that syntax can be checked.'.colorize(:yellow)
      status = :skipped
    end

  elsif erb_file? path
    errors = `cat #{path} | erb -x -T - | ruby -c 2>&1`
    status = $?.success? ? :passed : :failed

  elsif python_file? path
    if system('which python >/dev/null')
      errors = `python -m py_compile #{path} 2>&1`
      status = $?.success? ? :passed : :failed
    else
      puts 'Consider installing python so that syntax can be checked.'.colorize(:yellow)
      status = :skipped
    end

  elsif ruby_file? path
    errors = `ruby -c #{path} 2>&1`
    status = $?.success? ? :passed : :failed

  elsif perl_file? path
    if system('which perl >/dev/null')
      errors = `perl -c #{path} 2>&1`
      status = $?.success? ? :passed : :failed
    else
      puts 'Consider installing perl so that syntax can be checked.'.colorize(:yellow)
      status = :skipped
    end

  elsif bash_file? path
    errors = `bash -n #{path} 2>&1`.to_i
    status = $?.success? ? :passed : :failed

  # GitLab CI files need to be processed before YAML
  elsif gitlab_ci_file? path
    ci_content = YAML.load_file(path)

    if ENV.has_key?('CI_LINT_TOKEN')
      priv_token = ENV['CI_LINT_TOKEN']
    else
      token_file = "#{Dir.home}/.gitlab-tokens"
      if File.readable?(token_file)
        tokens = YAML.load_file(token_file)
        # Any token should work
        priv_token = tokens.values()[0]
      end
    end

    begin
      uri = URI.parse('https://gitlab.com/api/v4/ci/lint')
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = true
      Net::HTTP.enable_debug!
      request = Net::HTTP::Post.new(uri.path, {
                  'Content-Type' => 'application/json',
                  'Accept' => 'application/json',
                  'PRIVATE-TOKEN' => priv_token
                })
      request.body = {content: ci_content.to_json}.to_json
      response = http.request(request)
      puts response
    rescue => e
      puts "Exception: #{e}"
    end
    results = JSON.parse(response.body)
    case results['status']
    when 'valid'
      status = :passed
    when 'invalid'
      status = :failed
      errors = results['errors']
    end

  elsif json_file? path
    begin
      JSON.parse(File.read(path))
      status = :passed
    rescue Exception => e
      errors = e.message
      status = :failed
    end

  elsif yaml_file? path
    begin
      YAML.parse(File.read(path))
      status = :passed
    rescue Exception => e
      errors = e.message
      status = :failed
    end
  end

  if block_given?
    yield path, status, errors
  else
    show_status(path, status, errors)
    error_count += 1 if status == :failed
  end
end

.erb_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/check_file_syntax.rb', line 55

def erb_file?(path)
  type_of_file(path, :erb, '.erb')
end

.gitlab_ci_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/check_file_syntax.rb', line 83

def gitlab_ci_file?(path)
  type_of_file(path, :gitlab_ci, '.gitlab-ci.yml')
end

.json_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/check_file_syntax.rb', line 75

def json_file?(path)
  type_of_file(path, :json, '.json')
end

.perl_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/check_file_syntax.rb', line 67

def perl_file?(path)
  type_of_file(path, :perl, ['.pl', '.pm'])
end

.puppet_file?(path) ⇒ Boolean

define a bunch of convenience functions

Returns:

  • (Boolean)


51
52
53
# File 'lib/check_file_syntax.rb', line 51

def puppet_file?(path)
  type_of_file(path, :puppet, '.pp')
end

.python_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
# File 'lib/check_file_syntax.rb', line 59

def python_file?(path)
  type_of_file(path, :python, '.py')
end

.ruby_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/check_file_syntax.rb', line 63

def ruby_file?(path)
  type_of_file(path, :ruby, ['.rb', '.rake', 'rakefile', 'Rakefile'])
end

.search_all_files_for_errors(directory, excludes = [], checks = ALL_CHECKS, &block) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/check_file_syntax.rb', line 102

def search_all_files_for_errors(directory, excludes=[], checks=ALL_CHECKS, &block)
  error_count = 0
  Find.find(directory) do |path|
    # prune the directory tree if we found a directory that should be excluded
    if File.directory? path
      if not (excludes.select { |d| path.end_with? d }).empty?
        Find.prune
      else
        # we don't do any thing with dirs, so go to next item
        next
      end
    end

    # TODO Need to look at checks to determine if we should do this
    check_file_syntax(path) do |path, status, errors|
      if status == :failed
        error_count += 1
      end

      if block_given?
        yield path, status, errors
      else
        show_status(path, status, errors)
      end
    end
  end
  return error_count
end

.show_status(name, success, errors) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/check_file_syntax.rb', line 88

def show_status (name, success, errors)
  # Untested files return a nil success
  unless success.nil?
    if success == :passed
      puts '   OK   '.colorize(:green) + "  #{name}".colorize(:cyan)
    else
      puts '  FAIL  '.colorize(:light_yellow).swap + "  #{name}".colorize(:cyan)
      puts errors
    end
  end
end

.type_of_file(path, interpreter, extensions) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/check_file_syntax.rb', line 35

def type_of_file(path, interpreter, extensions)
  # check extensions first
  [extensions].flatten.each {|ext| return true if path.end_with? ext }

  # check only if really a file and is not 0 byte
  if File.file?(path) and File.size?(path)
    # Look for a she-bang line and check for interpreter
    shebang = File.open(path).first
    if shebang and shebang.start_with? '#!/' and shebang.include? interpreter.to_s
      return true
    end
  end
  return false
end

.yaml_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/check_file_syntax.rb', line 79

def yaml_file?(path)
  type_of_file(path, '---', ['.yaml', '.yml'])
end