gitlab-ci-yaml_lint 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE +20 -0
  7. data/README.md +50 -0
  8. data/Rakefile +6 -0
  9. data/bin/gitlab-ci-yaml_lint +13 -0
  10. data/gitlab-ci-yaml_lint.gemspec +31 -0
  11. data/gitlab_lib/LICENSE +27 -0
  12. data/gitlab_lib/gitlab/ci/config.rb +62 -0
  13. data/gitlab_lib/gitlab/ci/config/entry/artifacts.rb +35 -0
  14. data/gitlab_lib/gitlab/ci/config/entry/attributable.rb +27 -0
  15. data/gitlab_lib/gitlab/ci/config/entry/boolean.rb +18 -0
  16. data/gitlab_lib/gitlab/ci/config/entry/cache.rb +45 -0
  17. data/gitlab_lib/gitlab/ci/config/entry/commands.rb +33 -0
  18. data/gitlab_lib/gitlab/ci/config/entry/configurable.rb +77 -0
  19. data/gitlab_lib/gitlab/ci/config/entry/coverage.rb +22 -0
  20. data/gitlab_lib/gitlab/ci/config/entry/environment.rb +83 -0
  21. data/gitlab_lib/gitlab/ci/config/entry/factory.rb +73 -0
  22. data/gitlab_lib/gitlab/ci/config/entry/global.rb +72 -0
  23. data/gitlab_lib/gitlab/ci/config/entry/hidden.rb +22 -0
  24. data/gitlab_lib/gitlab/ci/config/entry/image.rb +47 -0
  25. data/gitlab_lib/gitlab/ci/config/entry/job.rb +157 -0
  26. data/gitlab_lib/gitlab/ci/config/entry/jobs.rb +52 -0
  27. data/gitlab_lib/gitlab/ci/config/entry/key.rb +22 -0
  28. data/gitlab_lib/gitlab/ci/config/entry/legacy_validation_helpers.rb +61 -0
  29. data/gitlab_lib/gitlab/ci/config/entry/node.rb +101 -0
  30. data/gitlab_lib/gitlab/ci/config/entry/paths.rb +18 -0
  31. data/gitlab_lib/gitlab/ci/config/entry/policy.rb +53 -0
  32. data/gitlab_lib/gitlab/ci/config/entry/script.rb +18 -0
  33. data/gitlab_lib/gitlab/ci/config/entry/service.rb +34 -0
  34. data/gitlab_lib/gitlab/ci/config/entry/services.rb +41 -0
  35. data/gitlab_lib/gitlab/ci/config/entry/simplifiable.rb +43 -0
  36. data/gitlab_lib/gitlab/ci/config/entry/stage.rb +22 -0
  37. data/gitlab_lib/gitlab/ci/config/entry/stages.rb +22 -0
  38. data/gitlab_lib/gitlab/ci/config/entry/undefined.rb +40 -0
  39. data/gitlab_lib/gitlab/ci/config/entry/unspecified.rb +19 -0
  40. data/gitlab_lib/gitlab/ci/config/entry/validatable.rb +38 -0
  41. data/gitlab_lib/gitlab/ci/config/entry/validator.rb +26 -0
  42. data/gitlab_lib/gitlab/ci/config/entry/validators.rb +144 -0
  43. data/gitlab_lib/gitlab/ci/config/entry/variables.rb +26 -0
  44. data/gitlab_lib/gitlab/ci/config/loader.rb +25 -0
  45. data/gitlab_lib/gitlab/ci/yaml_processor.rb +189 -0
  46. data/lib/gitlab/ci/yaml_lint.rb +73 -0
  47. data/lib/gitlab/ci/yaml_lint/rake/tasks.rb +28 -0
  48. data/lib/gitlab/ci/yaml_lint/version.rb +7 -0
  49. metadata +203 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e4f6d9c2aa26ac38285627c6da74edd327b5f126
4
+ data.tar.gz: 4faab9a496ceafa4375edbc09c25b7e5bbac40e2
5
+ SHA512:
6
+ metadata.gz: fc20d3ccae4fe802613350771387f7edc9f7e1b1ffc999b3a125fd11143b8aecf9a633a4d04dcf4468f52360e035337d3d016e49f15a8a9876a90881e096a2a8
7
+ data.tar.gz: 8a98a239d4421d2cfddc06b79076e215fd6d46d8f0aab5a00b8cc1c609a9e1b4d8e606252880139862eb575145b9674343431bd2937bf937405e200a667b695e
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ Gemfile.lock
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ before_install: gem install bundler
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in gitlab-ci-yaml_lint.gemspec
6
+ gemspec
7
+
8
+ gem 'pry'
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 Trevor Vaughan
2
+
3
+ This package is licensed under the Apache 2.0 license except for items covered
4
+ explicitly under other license terms.
5
+
6
+ Please see the various files for alternate licenses.
7
+
8
+ -----
9
+
10
+ Licensed under the Apache License, Version 2.0 (the "License");
11
+ you may not use this file except in compliance with the License.
12
+ You may obtain a copy of the License at
13
+
14
+ http://www.apache.org/licenses/LICENSE-2.0
15
+
16
+ Unless required by applicable law or agreed to in writing, software
17
+ distributed under the License is distributed on an "AS IS" BASIS,
18
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ See the License for the specific language governing permissions and
20
+ limitations under the License.
@@ -0,0 +1,50 @@
1
+ # Gitlab::Ci::YamlLint
2
+
3
+ This gem allows you to run a local validation of your `.gitlab-ci.yml` files.
4
+
5
+ Rake tasks are additionally include for validating your project
6
+ `.gitlab-ci.yml` files as part of your standard development workflow.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'gitlab-ci-yaml_lint'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install gitlab-ci-yaml_lint
23
+
24
+ ## Usage
25
+
26
+ You can validate a `.gitlab-ci.yml` file using the `gitlab-ci-yaml_lint`
27
+ application by passing it the path to your local `.gitlab-ci.yml` file.
28
+
29
+ To use the rake tasks, simply include the following in your project's `Rakefile`:
30
+
31
+ ```ruby
32
+ require 'gitlab/ci/yaml_lint/rake/tasks'
33
+
34
+ Gitlab::Ci::YamlLint::Rake::Tasks.new(File.dirname(__FILE__))
35
+ ```
36
+
37
+ This will result in tasks being created under the `gitlab_ci` namespace.
38
+
39
+ You can get a full listing by running `rake -D gitlab_ci`.
40
+
41
+ ## Development
42
+
43
+ After checking out the repo, run `bundle install` to install dependencies.
44
+ Then, run `rake spec` to run the tests.
45
+
46
+ To install this gem onto your local machine, run `bundle exec rake install`.
47
+
48
+ ## Contributing
49
+
50
+ Bug reports and pull requests are welcome on GitHub at https://github.com/trevor-vaughan/gitlab-ci-yaml_lint.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "gitlab/ci/yaml_lint"
5
+
6
+ infile = ARGV.shift
7
+
8
+ unless infile
9
+ $stderr.puts("Usage #{$0} <path/to/.gitlab-ci.yml>")
10
+ exit 1
11
+ end
12
+
13
+ Gitlab::Ci::YamlLint.validate(infile)
@@ -0,0 +1,31 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "gitlab/ci/yaml_lint/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gitlab-ci-yaml_lint"
8
+ spec.version = Gitlab::Ci::YamlLint::VERSION
9
+ spec.authors = ["Trevor Vaughan"]
10
+ spec.email = ["tvaughan@onyxpoint.com"]
11
+
12
+ spec.summary = %q{Validate your gitlab-ci.yml files}
13
+ spec.homepage = "https://github.com/trevor-vaughan/rubygem-gitlab-ci-yaml_lint"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib", 'gitlab_lib']
21
+
22
+ spec.add_runtime_dependency "activesupport", "~> 5.0.6"
23
+ spec.add_runtime_dependency "activemodel", "~> 5.0.6"
24
+ spec.add_runtime_dependency "activerecord", "~> 5.0.6"
25
+ spec.add_runtime_dependency "chronic", "~> 0.10.2"
26
+ spec.add_runtime_dependency "chronic_duration", "~> 0.10.6"
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.16"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rspec", "~> 3.0"
31
+ end
@@ -0,0 +1,27 @@
1
+ The files under this directory fall under the following license:
2
+
3
+ Copyright (c) 2011-2017 GitLab B.V.
4
+
5
+ With regard to the GitLab Software:
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
24
+
25
+ For all third party components incorporated into the GitLab Software, those
26
+ components are licensed under the original license provided by the owner of the
27
+ applicable component.
@@ -0,0 +1,62 @@
1
+ module Gitlab
2
+ module Ci
3
+ ##
4
+ # Base GitLab CI Configuration facade
5
+ #
6
+ class Config
7
+ def initialize(config)
8
+ @config = Loader.new(config).load!
9
+
10
+ @global = Entry::Global.new(@config)
11
+ @global.compose!
12
+ end
13
+
14
+ def valid?
15
+ @global.valid?
16
+ end
17
+
18
+ def errors
19
+ @global.errors
20
+ end
21
+
22
+ def to_hash
23
+ @config
24
+ end
25
+
26
+ ##
27
+ # Temporary method that should be removed after refactoring
28
+ #
29
+ def before_script
30
+ @global.before_script_value
31
+ end
32
+
33
+ def image
34
+ @global.image_value
35
+ end
36
+
37
+ def services
38
+ @global.services_value
39
+ end
40
+
41
+ def after_script
42
+ @global.after_script_value
43
+ end
44
+
45
+ def variables
46
+ @global.variables_value
47
+ end
48
+
49
+ def stages
50
+ @global.stages_value
51
+ end
52
+
53
+ def cache
54
+ @global.cache_value
55
+ end
56
+
57
+ def jobs
58
+ @global.jobs_value
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,35 @@
1
+ module Gitlab
2
+ module Ci
3
+ class Config
4
+ module Entry
5
+ ##
6
+ # Entry that represents a configuration of job artifacts.
7
+ #
8
+ class Artifacts < Node
9
+ include Validatable
10
+ include Attributable
11
+
12
+ ALLOWED_KEYS = %i[name untracked paths when expire_in].freeze
13
+
14
+ attributes ALLOWED_KEYS
15
+
16
+ validations do
17
+ validates :config, type: Hash
18
+ validates :config, allowed_keys: ALLOWED_KEYS
19
+
20
+ with_options allow_nil: true do
21
+ validates :name, type: String
22
+ validates :untracked, boolean: true
23
+ validates :paths, array_of_strings: true
24
+ validates :when,
25
+ inclusion: { in: %w[on_success on_failure always],
26
+ message: 'should be on_success, on_failure ' \
27
+ 'or always' }
28
+ validates :expire_in, duration: true
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ module Gitlab
2
+ module Ci
3
+ class Config
4
+ module Entry
5
+ module Attributable
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ def attributes(*attributes)
10
+ attributes.flatten.each do |attribute|
11
+ if method_defined?(attribute)
12
+ raise ArgumentError, 'Method already defined!'
13
+ end
14
+
15
+ define_method(attribute) do
16
+ return unless config.is_a?(Hash)
17
+
18
+ config[attribute]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module Gitlab
2
+ module Ci
3
+ class Config
4
+ module Entry
5
+ ##
6
+ # Entry that represents a boolean value.
7
+ #
8
+ class Boolean < Node
9
+ include Validatable
10
+
11
+ validations do
12
+ validates :config, boolean: true
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,45 @@
1
+ module Gitlab
2
+ module Ci
3
+ class Config
4
+ module Entry
5
+ ##
6
+ # Entry that represents a cache configuration
7
+ #
8
+ class Cache < Node
9
+ include Configurable
10
+ include Attributable
11
+
12
+ ALLOWED_KEYS = %i[key untracked paths policy].freeze
13
+ DEFAULT_POLICY = 'pull-push'.freeze
14
+
15
+ validations do
16
+ validates :config, allowed_keys: ALLOWED_KEYS
17
+ validates :policy, inclusion: { in: %w[pull-push push pull], message: 'should be pull-push, push, or pull' }, allow_blank: true
18
+ end
19
+
20
+ entry :key, Entry::Key,
21
+ description: 'Cache key used to define a cache affinity.'
22
+
23
+ entry :untracked, Entry::Boolean,
24
+ description: 'Cache all untracked files.'
25
+
26
+ entry :paths, Entry::Paths,
27
+ description: 'Specify which paths should be cached across builds.'
28
+
29
+ helpers :key
30
+
31
+ attributes :policy
32
+
33
+ def value
34
+ result = super
35
+
36
+ result[:key] = key_value
37
+ result[:policy] = policy || DEFAULT_POLICY
38
+
39
+ result
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,33 @@
1
+ module Gitlab
2
+ module Ci
3
+ class Config
4
+ module Entry
5
+ ##
6
+ # Entry that represents a job script.
7
+ #
8
+ class Commands < Node
9
+ include Validatable
10
+
11
+ validations do
12
+ include LegacyValidationHelpers
13
+
14
+ validate do
15
+ unless string_or_array_of_strings?(config)
16
+ errors.add(:config,
17
+ 'should be a string or an array of strings')
18
+ end
19
+ end
20
+
21
+ def string_or_array_of_strings?(field)
22
+ validate_string(field) || validate_array_of_strings(field)
23
+ end
24
+ end
25
+
26
+ def value
27
+ Array(@config)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,77 @@
1
+ module Gitlab
2
+ module Ci
3
+ class Config
4
+ module Entry
5
+ ##
6
+ # This mixin is responsible for adding DSL, which purpose is to
7
+ # simplifly process of adding child nodes.
8
+ #
9
+ # This can be used only if parent node is a configuration entry that
10
+ # holds a hash as a configuration value, for example:
11
+ #
12
+ # job:
13
+ # script: ...
14
+ # artifacts: ...
15
+ #
16
+ module Configurable
17
+ extend ActiveSupport::Concern
18
+
19
+ included do
20
+ include Validatable
21
+
22
+ validations do
23
+ validates :config, type: Hash
24
+ end
25
+ end
26
+
27
+ def compose!(deps = nil)
28
+ return unless valid?
29
+
30
+ self.class.nodes.each do |key, factory|
31
+ factory
32
+ .value(config[key])
33
+ .with(key: key, parent: self)
34
+
35
+ entries[key] = factory.create!
36
+ end
37
+
38
+ yield if block_given?
39
+
40
+ entries.each_value do |entry|
41
+ entry.compose!(deps)
42
+ end
43
+ end
44
+
45
+ class_methods do
46
+ def nodes
47
+ Hash[(@nodes || {}).map { |key, factory| [key, factory.dup] }]
48
+ end
49
+
50
+ private # rubocop:disable Lint/UselessAccessModifier
51
+
52
+ def entry(key, entry, metadata)
53
+ factory = Entry::Factory.new(entry)
54
+ .with(description: metadata[:description])
55
+
56
+ (@nodes ||= {}).merge!(key.to_sym => factory)
57
+ end
58
+
59
+ def helpers(*nodes)
60
+ nodes.each do |symbol|
61
+ define_method("#{symbol}_defined?") do
62
+ entries[symbol]&.specified?
63
+ end
64
+
65
+ define_method("#{symbol}_value") do
66
+ return unless entries[symbol] && entries[symbol].valid?
67
+
68
+ entries[symbol].value
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end