Class: Simp::Ci::Gitlab
- Inherits:
-
Object
- Object
- Simp::Ci::Gitlab
- Defined in:
- lib/simp/ci/gitlab.rb
Overview
Class that provides GitLab-CI-related methods
Defined Under Namespace
Classes: Error, JobError, LintError
Instance Method Summary collapse
-
#acceptance_job?(config) ⇒ Boolean
True when config is the hash for an acceptance test job.
-
#acceptance_tests? ⇒ Boolean
Whether the project has any suite-based acceptance tests.
-
#find_nodeset_yaml(suite, nodeset) ⇒ Object
If the suite has no ‘nodesets’ directory, it will search for the nodeset YAML in the global nodeset directory.
-
#initialize(component_dir) ⇒ Gitlab
constructor
A new instance of Gitlab.
-
#load_gitlab_yaml ⇒ Object
Loads .gitlab-ci.yml.
- #valid_suite?(suite) ⇒ Boolean
-
#validate_acceptance_test_jobs ⇒ Object
Validate GitLab acceptance test job specifications.
-
#validate_config ⇒ Object
Validate gitlab configuration.
-
#validate_yaml ⇒ Object
Verifies gitlab-ci.yml is valid YAML and, when possible, passes GitLab lint checks.
Constructor Details
#initialize(component_dir) ⇒ Gitlab
Returns a new instance of Gitlab.
19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/simp/ci/gitlab.rb', line 19 def initialize(component_dir) @component_dir = component_dir @gitlab_config_file = File.join(@component_dir, '.gitlab-ci.yml') @gitlab_yaml = nil @acceptance_dir = File.join(@component_dir, 'spec', 'acceptance') @suites_dir = File.join(@acceptance_dir, 'suites') # for reporting purposes, just use the name of the component # directory as the component name @component = File.basename(component_dir) end |
Instance Method Details
#acceptance_job?(config) ⇒ Boolean
Returns true when config is the hash for an acceptance test job.
32 33 34 35 36 |
# File 'lib/simp/ci/gitlab.rb', line 32 def acceptance_job?(config) config.is_a?(Hash) && config.has_key?('script') && (config.has_key?('stage') && (config['stage'] == 'acceptance')) end |
#acceptance_tests? ⇒ Boolean
Returns whether the project has any suite-based acceptance tests.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/simp/ci/gitlab.rb', line 39 def acceptance_tests? tests_found = false suite_dirs = Dir.glob(File.join(@suites_dir, '*')) suite_dirs.delete_if { |x| ! File.directory?(x) } suite_dirs.each do |suite_dir| tests = Dir.glob(File.join(suite_dir, '*_spec.rb')) next if tests.empty? nodesets = Dir.glob(File.join(suite_dir, 'nodesets', '*.yml')) if nodesets.empty? nodesets = Dir.glob(File.join(@acceptance_dir, 'nodesets', '*.yml')) end unless nodesets.empty? tests_found = true break end end tests_found end |
#find_nodeset_yaml(suite, nodeset) ⇒ Object
If the suite has no ‘nodesets’ directory, it will search for the nodeset YAML in the global nodeset directory.
63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/simp/ci/gitlab.rb', line 63 def find_nodeset_yaml(suite, nodeset) nodeset_yml = nil suite_nodesets_dir = File.join(@suites_dir, suite, 'nodesets') if Dir.exist?(suite_nodesets_dir) nodeset_yml = File.join(suite_nodesets_dir, "#{nodeset}.yml") nodeset_yml = nil unless File.exist?(nodeset_yml) else nodeset_yml = File.join(@acceptance_dir, 'nodesets', "#{nodeset}.yml") nodeset_yml = nil unless File.exist?(nodeset_yml) end nodeset_yml end |
#load_gitlab_yaml ⇒ Object
Loads .gitlab-ci.yml
79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/simp/ci/gitlab.rb', line 79 def load_gitlab_yaml return @gitlab_yaml if @gitlab_yaml begin @gitlab_yaml = YAML.safe_load(File.read(@gitlab_config_file), filename: @gitlab_config_file, aliases: true) rescue Psych::SyntaxError => e msg = "ERROR: Malformed YAML: #{e.message}" raise LintError.new(msg) end @gitlab_yaml end |
#valid_suite?(suite) ⇒ Boolean
220 221 222 223 224 |
# File 'lib/simp/ci/gitlab.rb', line 220 def valid_suite?(suite) suite_dir = File.join(@suites_dir, suite) #TODO check for suites that have no tests? return Dir.exist?(suite_dir) end |
#validate_acceptance_test_jobs ⇒ Object
Validate GitLab acceptance test job specifications
Verify each acceptance test job specifies both a valid suite and a valid nodeset
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 130 131 132 133 134 135 136 |
# File 'lib/simp/ci/gitlab.rb', line 102 def validate_acceptance_test_jobs return unless File.exist?(@gitlab_config_file) failures = [] gitlab_yaml = load_gitlab_yaml gitlab_yaml.each do |key, value| next unless acceptance_job?(value) value['script'].each do |line| next unless line.include? 'beaker:suites' if line.include?('[') match = line.match(/beaker:suites\[([\w\-_]*)(,([\w\-_]*))?\]/) suite = match[1] nodeset = match[3] if ! valid_suite?(suite) failures << "#{@component} job '#{key}' uses invalid suite '#{suite}': '#{line}'" elsif nodeset.nil? failures << "#{@component} job '#{key}' missing nodeset: '#{line}'" elsif ! find_nodeset_yaml(suite, nodeset) failures << "#{@component} job '#{key}' uses invalid nodeset '#{nodeset}': '#{line}'" end else failures << "#{@component} job '#{key}' missing suite and nodeset: '#{line}'" end end end unless failures.empty? separator = "\n " msg = "Invalid GitLab acceptance test config:#{separator}#{failures.join(separator)}" raise JobError.new(msg) end end |
#validate_config ⇒ Object
Validate gitlab configuration
Validation performed
-
Verifies configuration file is valid YAML
–Verifies configuration file passes GitLab lint check, when connectivity
to GitLab is available
-
Verifies acceptance test job configuration has valid suites and nodesets
147 148 149 150 151 152 153 154 155 |
# File 'lib/simp/ci/gitlab.rb', line 147 def validate_config if File.exist?(@gitlab_config_file) validate_yaml validate_acceptance_test_jobs elsif acceptance_tests? # can't assume this is a failure, so just warn puts "WARNING: #{@component} has acceptance tests but no .gitlab-ci.yml" end end |
#validate_yaml ⇒ Object
Verifies gitlab-ci.yml is valid YAML and, when possible, passes GitLab lint checks
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 |
# File 'lib/simp/ci/gitlab.rb', line 160 def validate_yaml return unless File.exist?(@gitlab_config_file) # first check for malformed yaml gitlab_yaml = load_gitlab_yaml # apply GitLab lint check begin gitlab_config_json = gitlab_yaml.to_json rescue Exception => e # really should never get here.... puts "WARNING: Could not lint check #{@component}'s GitLab configuration: query could not be formed" return end curl ||= %x(which curl).strip if curl.empty? puts "WARNING: Could not lint check #{@component}'s GitLab configuration: Could not find 'curl'" return end query = [ curl, '--silent', '--header "Content-Type: application/json"', 'https://gitlab.com/api/v4/ci/lint', '--data', "'{\"content\":#{gitlab_config_json.dump}}'" ] result = `#{query.join(' ')}` status = :unknown errors = nil begin result_hash = JSON.load(result) # if stdout is empty, result_hash will be nil unless result_hash.nil? if result_hash.has_key?('status') if result_hash['status'] == 'valid' status = :valid else status = :invalid errors = result_hash['errors'] end end end rescue # stdout does not contain JSON...don't know what happened! end if status == :unknown puts "WARNING: Unable to lint check #{@component}'s GitLab configuration" elsif status == :invalid separator = "\n " msg = "ERROR: Invalid GitLab config:#{separator}#{errors.join(separator)}" raise LintError.new(msg) end end |