ci-syntax-tool 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/LICENSE +27 -0
  4. data/README.md +109 -0
  5. data/Rakefile +43 -0
  6. data/bin/ci-syntax-tool +12 -0
  7. data/ci-syntax-tool.gemspec +27 -0
  8. data/lib/ci-syntax-tool.rb +6 -0
  9. data/lib/ci-syntax-tool/checker.rb +63 -0
  10. data/lib/ci-syntax-tool/command_line.rb +229 -0
  11. data/lib/ci-syntax-tool/format/base.rb +50 -0
  12. data/lib/ci-syntax-tool/format/junit.rb +54 -0
  13. data/lib/ci-syntax-tool/format/progress.rb +60 -0
  14. data/lib/ci-syntax-tool/format_factory.rb +55 -0
  15. data/lib/ci-syntax-tool/language/base.rb +56 -0
  16. data/lib/ci-syntax-tool/language/yaml.rb +41 -0
  17. data/lib/ci-syntax-tool/language_factory.rb +41 -0
  18. data/lib/ci-syntax-tool/result.rb +134 -0
  19. data/lib/ci-syntax-tool/version.rb +10 -0
  20. data/rubocop.yml +11 -0
  21. data/test/features/.keep +0 -0
  22. data/test/features/command-line-help.feature +15 -0
  23. data/test/features/format-junit.feature +29 -0
  24. data/test/features/language-yaml.feature +34 -0
  25. data/test/features/pluggable-formatters.feature +42 -0
  26. data/test/features/pluggable-languages.feature +15 -0
  27. data/test/features/require-ruby.feature +38 -0
  28. data/test/features/step_definitions/cli_steps.rb +46 -0
  29. data/test/features/step_definitions/format_steps.rb +63 -0
  30. data/test/features/step_definitions/junit_steps.rb +57 -0
  31. data/test/features/step_definitions/language_steps.rb +39 -0
  32. data/test/features/step_definitions/require_steps.rb +38 -0
  33. data/test/features/support/feature_helper.rb +142 -0
  34. data/test/fixtures/.keep +0 -0
  35. data/test/fixtures/files/clean/README.md +6 -0
  36. data/test/fixtures/files/clean/ansiblish.yaml +12 -0
  37. data/test/fixtures/files/clean/kitchenish.yml +17 -0
  38. data/test/fixtures/files/clean/rubocopish.yaml +11 -0
  39. data/test/fixtures/files/error/bad-indentation.yaml +5 -0
  40. data/test/fixtures/files/error/missing-array-element.yaml +5 -0
  41. data/test/fixtures/files/error/unquoted-jinja-template.yaml +3 -0
  42. data/test/fixtures/files/error/very-high-yaml-version.yaml +3 -0
  43. data/test/fixtures/require/invalid.rb +6 -0
  44. data/test/fixtures/require/mock_format.rb +10 -0
  45. data/test/fixtures/require/second.rb +10 -0
  46. data/test/fixtures/require/valid.rb +10 -0
  47. data/test/unit/.keep +0 -0
  48. data/test/unit/format_factory_spec.rb +46 -0
  49. data/test/unit/language_factory_spec.rb +46 -0
  50. data/test/unit/result_spec.rb +18 -0
  51. data/test/unit/spec_helper.rb +31 -0
  52. metadata +201 -0
@@ -0,0 +1,10 @@
1
+ module CI
2
+ module Syntax
3
+ # CI::Syntax::Tool module
4
+ # Simple container for namespacing the project. Here, just the
5
+ # version string.
6
+ module Tool
7
+ VERSION = '0.1.0'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ Style/FileName:
2
+ Enabled: False
3
+
4
+ Metrics/MethodLength:
5
+ Max: 25
6
+
7
+ Style/TrailingWhitespace:
8
+ Enabled: False
9
+
10
+ Style/TrailingComma:
11
+ Enabled: False
File without changes
@@ -0,0 +1,15 @@
1
+ Feature: Command line help
2
+
3
+ In order to be able to learn about the options available for syntax checking
4
+ As a developer
5
+ I want to be able to interactively get help on the options from the command line
6
+
7
+ Scenario: Command help
8
+ Given I have installed the tool
9
+ When I run it on the command line with the help option
10
+ Then the simple usage text should be displayed along with a zero exit code
11
+
12
+ Scenario: Display version
13
+ Given I have installed the tool
14
+ When I run it on the command line with the version option
15
+ Then the current version should be displayed
@@ -0,0 +1,29 @@
1
+ Feature: jUnit / SureFire format
2
+
3
+ In order to be able to use the tool with many popular CI tools
4
+ As a developer
5
+ I want to be able to have output formatted as jUnit-style XML reports
6
+
7
+ Scenario: List available core formats
8
+ Given I have installed the tool
9
+ When I run it on the command line with the list-formats option
10
+ Then JUnit should be included in the listed formats
11
+
12
+ Scenario: Use JUnit format on clean files
13
+ Given I have installed the tool
14
+ When I run it on the command line with the JUnit format on clean files
15
+ Then I should get a 0 exit code
16
+ And the generated files should be valid XML
17
+ And the JUnit files should have the correct structure
18
+ And the JUnit files should have 0 errors
19
+ And the JUnit files should have 0 warnings
20
+
21
+ Scenario: Use JUnit format on error files
22
+ Given I have installed the tool
23
+ When I run it on the command line with the JUnit format on error files
24
+ Then I should get a 1 exit code
25
+ And the generated files should be valid XML
26
+ And the JUnit files should have the correct structure
27
+ And the JUnit files should have 3 errors
28
+ And the JUnit files should have 0 warnings
29
+
@@ -0,0 +1,34 @@
1
+ Feature: Pluggable formatters
2
+
3
+ In order to be able to check YAML files for errors
4
+ As a developer
5
+ I want to be able to run the tool on yaml files
6
+
7
+ Scenario: Use YAML explicitly on clean files
8
+ Given I have installed the tool
9
+ When I run it on the command line specifying the YAML language and clean files
10
+ Then I should get a 0 exit code
11
+ And the output should show only files for YAML
12
+ And the output should have 0 warnings
13
+ And the output should have 0 errors
14
+
15
+
16
+ Scenario: Run all lamnguages on clean files
17
+ Given I have installed the tool
18
+ When I run it on the command line specifying all languages and clean files
19
+ Then I should get a 0 exit code
20
+ And the output should include files for YAML
21
+ And the output should have 0 warnings
22
+ And the output should have 0 errors
23
+
24
+
25
+ Scenario: Use YAML explicitly on error files
26
+ Given I have installed the tool
27
+ When I run it on the command line specifying the YAML language and error files
28
+ Then I should get a 1 exit code
29
+ And the output should show only files for YAML
30
+ And the output should have 0 warnings
31
+ And the output should have 3 errors
32
+
33
+
34
+
@@ -0,0 +1,42 @@
1
+ Feature: Pluggable formatters
2
+
3
+ In order to be able to use the tool with whatever CI engine I need
4
+ As a developer
5
+ I want to be able to output the results of language checks in various formats
6
+
7
+ Scenario: List available core formats
8
+ Given I have installed the tool
9
+ When I run it on the command line with the list-formats option
10
+ Then I should get a list of the core formats along with a zero exit code
11
+
12
+ Scenario: Reject an invalid format
13
+ Given I have installed the tool
14
+ When I run it on the command line with the format option and the argument foo
15
+ Then I should get an error message and the exit code 4
16
+
17
+ Scenario: Reject multiple formats without destination
18
+ Given I have installed the tool
19
+ When I run it on the command line with two format options and 0 destinations
20
+ Then I should get an error message and the exit code 4
21
+
22
+ Scenario: Reject multiple formats with ambiguous destination count
23
+ Given I have installed the tool
24
+ When I run it on the command line with two format options and 1 destinations
25
+ Then I should get an error message and the exit code 4
26
+
27
+ Scenario: Use multiple formatters with correct number of destinations
28
+ Given I have installed the tool
29
+ When I run it on the command line with two format options and 2 destinations
30
+ Then I should get a 0 exit code
31
+
32
+ Scenario: Create destination files automatically
33
+ Given I have installed the tool
34
+ When I run it on the command line with a destination in the current directory
35
+ Then the file should be created
36
+
37
+ Scenario: Create destination directories automatically
38
+ Given I have installed the tool
39
+ When I run it on the command line with a destination in a directory that does not exist
40
+ Then the file should be created
41
+
42
+
@@ -0,0 +1,15 @@
1
+ Feature: Pluggable languages
2
+
3
+ In order to be able to use the tool on whatever language I need
4
+ As a developer
5
+ I want to be able to extend the tool by adding support for new languages
6
+
7
+ Scenario: List available core languages
8
+ Given I have installed the tool
9
+ When I run it on the command line with the list-languages option
10
+ Then I should get a list of the core languages along with a zero exit code
11
+
12
+ Scenario: Reject an invalid language
13
+ Given I have installed the tool
14
+ When I run it on the command line with the lang option and the argument foo
15
+ Then I should get an error message and the exit code 3
@@ -0,0 +1,38 @@
1
+ Feature: Load extra Ruby files
2
+
3
+ In order to be able to use the tool with custom plugins
4
+ As a developer
5
+ I want to be able to load additional ruby files
6
+
7
+ Scenario: Load a valid ruby file
8
+ Given I have installed the tool
9
+ When I run it on the command line with the require option and a valid ruby file
10
+ Then the valid ruby file should have been loaded
11
+ And I should get a 0 exit code
12
+
13
+ Scenario: Reject a missing file with a nice message
14
+ Given I have installed the tool
15
+ When I run it on the command line with the require option and a missing ruby file
16
+ Then I should get an error message about the missing require file
17
+ And I should get a 5 exit code
18
+
19
+ Scenario: Reject an invalid file with a nice message
20
+ Given I have installed the tool
21
+ When I run it on the command line with the require option and a invalid ruby file
22
+ Then I should get an error message about the invalid require file
23
+ And I should get a 5 exit code
24
+
25
+ Scenario: Reject an invalid file with a stacktrace when debug flag is present
26
+ Given I have installed the tool
27
+ When I run it on the command line with the require option and the debug option and a invalid ruby file
28
+ Then I should get a stack trace about the invalid require file
29
+ And I should get a 5 exit code
30
+
31
+ Scenario: Accept multiple requires
32
+ Given I have installed the tool
33
+ When I run it on the command line with two requires
34
+ Then the first ruby file should have been loaded
35
+ And the second ruby file should have been loaded
36
+ And I should get a 0 exit code
37
+
38
+
@@ -0,0 +1,46 @@
1
+ Given(/^I have installed the tool$/) do
2
+ end
3
+
4
+ # TODO: Add code to target fixture directory by default
5
+ When(/^I run it on the command line with the ([^ ]+) option(?: and the argument )?([^ ]+)?$/) do |option, arg|
6
+ options = []
7
+ if option.match(/\-\w$/)
8
+ options << option
9
+ else
10
+ options << "--#{option}"
11
+ end
12
+ if arg
13
+ options << arg
14
+ end
15
+ @run_result = run_check(options)
16
+ end
17
+
18
+ Then(/^the simple usage text should be displayed along with a non\-zero exit code$/) do
19
+ refute_empty(@run_result[:stderr], 'Expected to see an error message on STDERR')
20
+ refute_equal(@run_result[:exit_status], 0)
21
+ assert_usage_message
22
+ end
23
+
24
+ Then(/^the simple usage text should be displayed along with a zero exit code$/) do
25
+ assert_empty(@run_result[:stderr])
26
+ assert_equal(@run_result[:exit_status], 0)
27
+ assert_usage_message
28
+ end
29
+
30
+ Then(/^the current version should be displayed$/) do
31
+ assert_match(/^ci-syntax-tool/, @run_result[:stdout], 'Version string should include tool name')
32
+ assert_match(Regexp.new(Regexp.escape(CI::Syntax::Tool::VERSION)), @run_result[:stdout], 'Version string should include the version')
33
+ assert_equal(@run_result[:stdout].split("\n").length, 1, 'Version output should be exactly one line long')
34
+ assert_empty(@run_result[:stderr])
35
+ assert_equal(@run_result[:exit_status], 0)
36
+ end
37
+
38
+ Then(/^I should get an error message and the exit code (\d+)$/) do |expected_exit_status|
39
+ refute_empty(@run_result[:stderr], 'Expected to see an error message on STDERR')
40
+ assert_equal(expected_exit_status.to_i, @run_result[:exit_status])
41
+ end
42
+
43
+ Then(/^I should get a (\d+) exit code$/) do |expected_exit_status|
44
+ assert_equal(expected_exit_status.to_i, @run_result[:exit_status].to_i)
45
+ end
46
+
@@ -0,0 +1,63 @@
1
+ require 'fileutils'
2
+
3
+ When(/^I run it on the command line with two format options and (\d) destination(?:s)$/) do |dest_count|
4
+ options = [
5
+ '--require', Dir.pwd + '/' + 'test/fixtures/require/mock_format.rb',
6
+ '--format', 'MockFormat',
7
+ '--format', 'MockFormat',
8
+ ]
9
+ (0..(dest_count.to_i-1)).to_a.each do |i|
10
+ options << '--output'
11
+ options << 'test/tmp/dest-' + i.to_s
12
+ end
13
+ options << 'test/fixtures/files/clean'
14
+ @run_result = run_check(options)
15
+ end
16
+
17
+ When(/^I run it on the command line with a destination in (the current directory|a directory that does not exist)$/) do |mode|
18
+ path = 'output-create-test-1'
19
+ options = [
20
+ '--output'
21
+ ]
22
+ if mode == 'the current directory'
23
+ FileUtils.rm_f path
24
+ options << path
25
+ else
26
+ dir = 'test/tmp/output-create-dir'
27
+ FileUtils.rm_f dir
28
+ options << dir + '/' + path
29
+ end
30
+ options << 'test/fixtures/files/clean'
31
+ @expected_output_paths = [ path ]
32
+ @run_result = run_check(options)
33
+ end
34
+
35
+ When(/^I run it on the command line with the ([^ ]+) format on ([^ ]+) files$/) do |fmt_name, fixture|
36
+ path = "test/tmp/#{fmt_name}.out"
37
+ FileUtils.rm_f path
38
+ options = [
39
+ '--format', fmt_name,
40
+ '--output', path,
41
+ '--lang', 'YAML',
42
+ "test/fixtures/files/#{fixture}",
43
+ ]
44
+ @expected_output_paths = [ path ]
45
+ @run_result = run_check(options)
46
+ end
47
+
48
+ Then(/^I should get a list of the core formats along with a zero exit code$/) do
49
+ assert_equal(0, @run_result[:exit_status])
50
+ assert_format_list
51
+ end
52
+
53
+ Then(/^([^ ]+) should be included in the listed formats$/) do |fmt_name|
54
+ actual = @run_result[:stdout].split("\n")
55
+ assert_includes(actual, fmt_name)
56
+ end
57
+
58
+ Then(/^the file(?:s)? should be created$/) do
59
+ @expected_output_paths.each do |path|
60
+ assert(File.exist?(path), "#{path} should exist")
61
+ end
62
+ end
63
+
@@ -0,0 +1,57 @@
1
+ require 'nokogiri'
2
+
3
+ Then(/^the generated files should be valid XML$/) do
4
+ @expected_output_paths.each do |path|
5
+ begin
6
+ doc = File.open(path) { |f| Nokogiri::XML(f) }
7
+ pass
8
+ rescue
9
+ flunk
10
+ end
11
+ end
12
+ end
13
+
14
+ Then(/^the JUnit files should have the correct structure$/) do
15
+ @expected_output_paths.each do |path|
16
+
17
+ # puts "POINT A:" + path
18
+
19
+ doc = File.open(path) { |f| Nokogiri::XML(f) }
20
+
21
+ # puts "POINT B:" + doc.to_s
22
+ assert_equal(1, doc.xpath('/testsuites').length, "It should have one root testsuites element")
23
+
24
+ # It should have nonzero testsuite elements with a name attribute reflecting the language
25
+ match = doc.xpath('/testsuites/testsuite')
26
+ assert(match.length > 0, "It should have nonzero testsuite elements")
27
+ langs = CI::Syntax::Tool::LanguageFactory.all_language_names
28
+ match.each do |node|
29
+ assert_includes(langs, node.at_xpath('@name').to_s)
30
+ end
31
+
32
+ # It should have nonzero testcase elements, one per file, with name = sanitized filename
33
+ match = doc.xpath('/testsuites/testsuite/testcase')
34
+ assert(match.length > 0, "It should have nonzero testcase elements")
35
+ match.each do |node|
36
+ file = node.at_xpath('@name').to_s
37
+ refute_empty(file, "testcase should have a name attribute")
38
+ end
39
+
40
+ # It may have failure elements which must have a type=warning or error
41
+ match = doc.xpath('/testsuites/testsuite/testcase/failure')
42
+ match.each do |node|
43
+ type = node.at_xpath('@type').to_s
44
+ assert_includes(['warning', 'error'], type, "Each failure type should be either a warning or an error")
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ Then(/^the JUnit files should have (\d+) (error|warning)s$/) do |count, level|
51
+ actual_count = 0
52
+ @expected_output_paths.each do |path|
53
+ doc = File.open(path) { |f| Nokogiri::XML(f) }
54
+ actual_count += doc.xpath("//failure[@type=\"#{level}\"]").length
55
+ end
56
+ assert_equal(count.to_i, actual_count)
57
+ end
@@ -0,0 +1,39 @@
1
+ When(/^I run it on the command line specifying(?: the)? ([^ ]+) language(?:s)? and ([^ ]+) files$/) do |lang_name, fixture_group|
2
+ options = [
3
+ '--require', Dir.pwd + '/' + 'test/fixtures/require/mock_format.rb',
4
+ '--format', 'MockFormat',
5
+ ]
6
+ unless lang_name == 'all'
7
+ options << '--lang'
8
+ options << lang_name
9
+ end
10
+ options << 'test/fixtures/files/' + fixture_group
11
+
12
+ @run_result = run_check(options)
13
+ end
14
+
15
+ Then(/^I should get a list of the core languages along with a zero exit code$/) do
16
+ assert_equal(0, @run_result[:exit_status].to_i)
17
+ assert_language_list
18
+ end
19
+
20
+ Then(/^the output should have (\d+) (error|warning)s$/) do |count, level|
21
+ actual = @run_result[:overall_result].send((level +'_count').to_sym)
22
+ assert_equal(count.to_i, actual)
23
+ end
24
+
25
+ Then(/^the output should show only files for ([^ ]+)$/) do |lang_name|
26
+ touched = @run_result[:overall_result].file_paths
27
+ matched = files_matching_language(touched, lang_name)
28
+ extra = touched - matched
29
+ assert_empty(extra, "The touched files should ONLY include files for #{lang_name}")
30
+ refute_empty(matched, "The touched files should include files for #{lang_name}")
31
+ end
32
+
33
+
34
+ Then(/^the output should include files for ([^ ]+)$/) do | lang_name|
35
+ touched = @run_result[:overall_result].file_paths
36
+ matched = files_matching_language(touched, lang_name)
37
+ refute_empty(matched, "The touched files should include files for #{lang_name}")
38
+ end
39
+
@@ -0,0 +1,38 @@
1
+ When(/^I run it on the command line with the require option (and the debug option )?and a (valid|invalid|missing) ruby file$/) do |need_debug, require_file|
2
+ options = [
3
+ '--require', Dir.pwd + '/' + 'test/fixtures/require/' + require_file + '.rb',
4
+ ]
5
+ if need_debug then
6
+ options << '--debug'
7
+ end
8
+ options << 'test/fixtures/files/clean'
9
+ @run_result = run_check(options)
10
+ end
11
+
12
+ When(/^I run it on the command line with two requires$/) do
13
+ options = [
14
+ '--require', Dir.pwd + '/' + 'test/fixtures/require/valid.rb',
15
+ '--require', Dir.pwd + '/' + 'test/fixtures/require/second.rb',
16
+ ]
17
+ options << 'test/fixtures/files/clean'
18
+ @run_result = run_check(options)
19
+ end
20
+
21
+ Then(/^I should get an error message about the (missing|invalid) require file$/) do |which_require|
22
+ assert_match(Regexp.new("Could not load .+ because it appears to be #{which_require}."), @run_result[:stderr])
23
+ assert_equal(1, @run_result[:stderr].split("\n").length, 'Stderr should be a single line, not a nasty stacktrace')
24
+ assert_empty(@run_result[:stdout], 'Stdout should be silent')
25
+ end
26
+
27
+ Then(/^I should get a stack trace about the invalid require file$/) do
28
+ assert_match(Regexp.new("Could not load .+ because it appears to be invalid."), @run_result[:stderr])
29
+ assert_match(Regexp.new('(Error|Exception)'),@run_result[:stderr], 'Stderr should include a stack trace')
30
+ assert_empty(@run_result[:stdout], 'Stdout should be silent')
31
+ end
32
+
33
+ Then(/^the (valid|first|second) ruby file should have been loaded$/) do |which_require|
34
+ klass_name = which_require == 'first' ? 'valid' : which_require
35
+ klass_name.capitalize!
36
+ klass_name = 'CI::Syntax::Tool::Test::' + klass_name + 'Require'
37
+ assert_class_loaded(klass_name)
38
+ end