Class: Danger::DangerSpelling

Inherits:
Plugin
  • Object
show all
Defined in:
lib/spelling/plugin.rb

Overview

This is a Danger plugin that wraps the python library pyspelling and some of its usage. The pyspelling results are posted to the pull request as a comment with the spelling mistake, file path & line number where the spelling mistake was found.

It has some dependencies that should be installed prior to running.

Your repository will also require a .pyspelling.yml file to be present. This .pyspelling.yml can be basic, but it will require a name and source property. Its advisable to include ‘expect_match: false` in your test matrix. This will stop pyspelling from generating an error at runtime.

There are several ways to use this danger plugin

added in the given pull request.

spelling.name = "test_matrix"
spelling.check_spelling

request, excluding some specific file names

spelling.ignored_files = ["Gemfile"]
spelling.name = "test_matrix"
spelling.check_spelling

request, excluding some specific file names and excluding some words

spelling.ignored_words = ["HammyAssassin"]
spelling.ignored_files = ["Gemfile"]
spelling.name = "test_matrix"
spelling.check_spelling

Examples:

execute pyspelling matrix with the name ‘test_matrix’ on all files modified or

execute pyspelling matrix with the name ‘test_matrix’ on all files modified or added in the given pull

execute pyspelling matrix with the name ‘test_matrix’ on all files modified or added in the given pull

See Also:

  • HammyAssassin/danger-spelling
  • HammyAssassin/danger-spelling
  • HammyAssassin/danger-spelling

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#ignored_filesArray<String>

Allows you to ignore certain files that might otherwise be scanned by pyspelling. The default value is [] for when its nil

Returns:

  • (Array<String>)


62
63
64
# File 'lib/spelling/plugin.rb', line 62

def ignored_files
  @ignored_files
end

#ignored_wordsArray<String>

Allows you to ignore certain words that might otherwise be detected as a spelling error. default value is [] when its nil

Returns:

  • (Array<String>)


56
57
58
# File 'lib/spelling/plugin.rb', line 56

def ignored_words
  @ignored_words
end

#name<String>

required The name of the test matrix in your .pyspelling.yml An exception will be raised if this is not specified in your Danger file.

Returns:

  • (<String>)


68
69
70
# File 'lib/spelling/plugin.rb', line 68

def name
  @name
end

Instance Method Details

#aspell_hunspell_installed?<Bool>

**Internal Method**

checks if aspell and hunspell are installed.

Returns:

  • (<Bool>)


341
342
343
# File 'lib/spelling/plugin.rb', line 341

def aspell_hunspell_installed?
  aspell_installed? && hunspell_installed?
end

#aspell_installed?<Bool>

**Internal Method**

Checks if aspell is installed.

Returns:

  • (<Bool>)


317
318
319
# File 'lib/spelling/plugin.rb', line 317

def aspell_installed?
  'which aspell'.strip.empty? == false
end

#check_for_dependanciesVoid

**Internal Method**

Check for dependencies. Raises exception if pyspelling, hunspell or aspell are not installed.

Returns:

  • (Void)


248
249
250
251
252
# File 'lib/spelling/plugin.rb', line 248

def check_for_dependancies
  raise 'pyspelling is not in the users PATH, or it failed to install.' unless pyspelling_installed?

  raise 'aspell or hunspell must be installed in order for pyspelling to work.' unless aspell_hunspell_installed?
end

#check_spelling(files = nil) ⇒ void

This method returns an undefined value.

Checks the spelling of all files added or modified in a given pull request. This will fail if pyspelling cannot be installed if not installed already. It will fail if ‘aspell` or `hunspell` are not detected.

It will also fail if the required parameter ‘name` hasn’t been specificed in the Danger file.

modified files will be scanned.

Parameters:

  • files (<Danger::FileList>) (defaults to: nil)

    Optional files to be scanned. Default value is nil. If nil, added and



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/spelling/plugin.rb', line 82

def check_spelling(files = nil)
  raise 'name must be a valid matrix name in your .pyspelling.yml.' if name.nil? || name.empty?

  check_for_dependancies

  new_files = get_files files
  results_texts = pyspelling_results(new_files)

  spell_issues = results_texts.select { |_, output| output.include? 'Spelling check failed' }

  # Get some metadata about the local setup
  current_slug = env.ci_source.repo_slug

  update_message_for_issues(spell_issues, current_slug) if spell_issues.count.positive?
end

#find_word_in_text(text, word) ⇒ <Bool>

**Internal Method**

splits a line of text up and checks if the spelling error is a match.

Parameters:

  • text (<String>)

    the string to be split and checked.

  • word (<String>)

    the word to find in text.

Returns:

  • (<Bool>)

    if the word is found.



171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/spelling/plugin.rb', line 171

def find_word_in_text(text, word)
  val = false
  line_array = text.split
  line_array.each do |array_item|
    array_item = array_item[0...array_item.size - 1] if array_item[-1] == '.'
    # puts "array_item #{array_item}"
    # puts "is url #{is_url(array_item.strip)}"
    if array_item.strip == word.strip && !url?(array_item.strip)
      val = true
      val
    end
  end
  val
end

#get_files(files) ⇒ <Danger::FileList>

**Internal Method**

Gets a file list of the files provided or finds modified and added files to scan. If files are provided via ‘ignored_files` they will be removed from the final returned list.

Will raise an exception if no files are found.

Parameters:

  • files (<Danger::FileList>)

    FileList to scan. Can be nil.

Returns:

  • (<Danger::FileList>)

    a FileList of files found.



359
360
361
362
363
364
365
366
367
368
# File 'lib/spelling/plugin.rb', line 359

def get_files(files)
  # Use either the files provided, or the modified & added files.
  found_files = files ? Dir.glob(files) : (git.modified_files + git.added_files)
  raise 'No files found to check' if found_files.nil?

  ignored_files.each do |file|
    found_files.delete(file)
  end
  found_files
end

#git_check(current_slug, path) ⇒ <String>

**Internal Method**

Check on the git service used. Will raise an error if using bitbucket as it currently doesnt support that.

Parameters:

  • current_slug (<String>)

    the current repo slug. eg. hamstringassassin/danger-spelling.

  • path (<String>)

    path to file.

Returns:

  • (<String>)

    full path to file including branch.



230
231
232
233
234
235
236
237
238
# File 'lib/spelling/plugin.rb', line 230

def git_check(current_slug, path)
  if defined? @dangerfile.github
    "/#{current_slug}/tree/#{github.branch_for_head}/#{path}"
  elsif defined? @dangerfile.gitlab
    "/#{current_slug}/tree/#{gitlab.branch_for_head}/#{path}"
  else
    raise 'This plugin does not yet support bitbucket'
  end
end

#hunspell_installed?<Bool>

**Internal Method**

Checks if Hunspell is installed.

Returns:

  • (<Bool>)


329
330
331
# File 'lib/spelling/plugin.rb', line 329

def hunspell_installed?
  'which hunspell'.strip.empty? == false
end

#ignore_line(text, file_path) ⇒ <Bool>

**Internal Method**

Checks if a given line can be ignored if it contains expected pyspelling output.

Parameters:

  • text (<String>)

    the text to check.

  • file_path (<String>)

    the file path to check.

Returns:

  • (<Bool>)

    if the line can be ignored.



265
266
267
268
269
270
271
# File 'lib/spelling/plugin.rb', line 265

def ignore_line(text, file_path)
  text.strip == 'Misspelled words:' ||
    text.strip == "<text> #{file_path}" ||
    text.strip == '!!!Spelling check failed!!!' ||
    text.strip == '--------------------------------------------------------------------------------' ||
    text.strip == ''
end

#message_title(message, path, git_loc) ⇒ <String>

**Internal Method**

appends the default message when a spelling error is found.

Parameters:

  • message (<String>)

    the message to append

  • path (<String>)

    the path of the file

  • git_loc (<String>)

    the git location of the file

Returns:

  • (<String>)

    formatted message



153
154
155
156
157
158
# File 'lib/spelling/plugin.rb', line 153

def message_title(message, path, git_loc)
  message << "#### [#{path}](#{git_loc})\n\n"
  message << "Line | Typo |\n "
  message << "| --- | ------ |\n "
  message
end

#pyspelling_installed?<Bool>

**Internal Method**

Checks of pyspelling is installed.

Returns:

  • (<Bool>)


305
306
307
# File 'lib/spelling/plugin.rb', line 305

def pyspelling_installed?
  'which pyspelling'.strip.empty? == false
end

#pyspelling_results(new_files) ⇒ Hash

**Internal Method**

Runs pyspelling on the test matrix name provided with any files given.

Parameters:

  • new_files (<Danger::FileList>)

    a list of files provided to scan with pyspelling.

Returns:

  • (Hash)

    returns a hash of the file scanned and any spelling errors found.



210
211
212
213
214
215
216
217
# File 'lib/spelling/plugin.rb', line 210

def pyspelling_results(new_files)
  results_texts = {}
  new_files.each do |file|
    file_result = `pyspelling --name '#{name}' --source '#{file}'`
    results_texts[file] = file_result
  end
  results_texts
end

#remove_ignored_words(spelling_errors, file_path) ⇒ <Array>

**Internal Method**

Removes some standard words in the pyspelling results. Words provided in ‘ignored_words` will also be removed from the results array.

Parameters:

  • spelling_errors (<Array>)

    Complete list of spelling errors.

  • file_path (<String>)

    file path.

Returns:

  • (<Array>)

    curated list of spelling errors, excluding standard and user defined words.



285
286
287
288
289
290
291
292
293
294
295
# File 'lib/spelling/plugin.rb', line 285

def remove_ignored_words(spelling_errors, file_path)
  spelling_errors.delete('Misspelled words:')
  spelling_errors.delete("<text> #{file_path}".strip)
  spelling_errors.delete('!!!Spelling check failed!!!')
  spelling_errors.delete('--------------------------------------------------------------------------------')
  spelling_errors.delete('')
  ignored_words.each do |word|
    spelling_errors.delete(word)
  end
  spelling_errors
end

#update_message_for_issues(spell_issues, current_slug) ⇒ Array<String>

**Internal Method**

Updates the message that will eventually be posted as a comment a pull request with a new line for each time the spelling error has been detected.

Parameters:

  • spell_issues (<Hash>)

    the Hash containing the file path & the detected mistakes.

  • current_slug (<String>)

    the repo. eg /hamstringassassin/danger-spelling.

Returns:

  • (Array<String>)

    an array of messages to be displayed in the PR comment.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/spelling/plugin.rb', line 110

def update_message_for_issues(spell_issues, current_slug)
  message = "### Spell Checker found issues\n\n"

  spell_issues.each do |path, output|
    git_loc = git_check(current_slug, path)
    error_message = ''
    error_message_updated = false
    error_message = message_title(error_message, path, git_loc)

    output_array = output.split(/\n/)
    output_array = remove_ignored_words(output_array, path)

    output_array.each do |txt|
      File.open(path, 'r') do |file_handle|
        file_handle.each_line do |path_line|
          if find_word_in_text(path_line, txt)
            error_message << "#{$INPUT_LINE_NUMBER} | #{txt} \n "
            error_message_updated = true
          end
        end
      end
    end
    if error_message_updated
      message << error_message
      error_message = ''
    end
  end
  markdown message
end

#url?(txt) ⇒ <Bool>

**Internal Method**

checks if a given String is a URL

Parameters:

  • txt (<String>)

    String to check

Returns:

  • (<Bool>)


196
197
198
# File 'lib/spelling/plugin.rb', line 196

def url?(txt)
  txt =~ /\A#{URI::DEFAULT_PARSER.make_regexp}\z/
end