gitlab-ci-yaml_lint 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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