Skip to content

Commit 40b4982

Browse files
author
dcs3spp
committed
initial commit
1 parent 2263016 commit 40b4982

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

.pre-commit-hooks.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
- id: validate-gitlab-ci
2+
name: Validate GitLab CI
3+
description: This hook validates the Gitlab CI yaml file
4+
entry: validate-ci
5+
files: [ .gitlab-ci.yaml ]
6+
language: ruby
7+
language_version: 2.6.3p62
8+
types: [executable, file, ruby, text]
9+
verbose: true

validate.rb

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/usr/bin/env ruby
2+
3+
4+
require 'json'
5+
require 'net/http'
6+
require 'optparse'
7+
require 'yaml'
8+
9+
10+
=begin
11+
POST to GitLab api for linting ci yaml
12+
Params:
13+
+url+ :: Api url
14+
+yaml+ :: Yaml payload for linting
15+
Returns:
16+
Json validation result from API for HTTP response Success
17+
Aborts with HTTP Message for all other status codes
18+
=end
19+
def call_api(url, yaml)
20+
uri = URI.parse(url)
21+
22+
req = Net::HTTP::Post.new(uri)
23+
req.content_type='application/json'
24+
req['Accept']='application/json'
25+
req.body = JSON.dump({"content" => yaml.to_json})
26+
27+
https = Net::HTTP.new(uri.host, uri.port)
28+
https.use_ssl = true
29+
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
30+
31+
response = https.request(req)
32+
33+
case response
34+
when Net::HTTPSuccess
35+
puts "request successful"
36+
return JSON.parse response.body
37+
when Net::HTTPUnauthorized
38+
abort("#{response.message}: invalid token in api request?")
39+
when Net::HTTPServerError
40+
abort('error' => "#{response.message}: server error, try again later?")
41+
when Net::HTTPBadRequest
42+
puts "Bad request..." + request.body
43+
abort("#{response.message}: bad api request?")
44+
when Net::HTTPNotFound
45+
abort("#{response.message}: api request not found?")
46+
else
47+
puts "Failed validation\nJSON payload :: #{request.body}\nHTTP Response: #{response.message}"
48+
abort("#{response.message}: failed api request?")
49+
end
50+
end
51+
52+
53+
=begin
54+
Display exit report and raise the appropriate system exit code
55+
Params:
56+
+status+ :: Validation status string. Legal values are valid or invalid
57+
+errors+ :: String array storing errors if yaml was reported as invalid
58+
Returns:
59+
Exits with 0 when successful
60+
Exits with 1 on validation errors or fails to parse legal status value
61+
=end
62+
def exit_report(status, errors)
63+
case status
64+
when "valid"
65+
puts ".gitlab-ci.yml is valid"
66+
exit(0)
67+
when "invalid"
68+
abort(".gitlab-ci.yml is invalid with errors:\n\n" + errors.join("\n"))
69+
else
70+
abort("A problem was encountered parsing status : " + status)
71+
end
72+
end
73+
74+
75+
=begin
76+
Load yaml file from path and return contents
77+
Params:
78+
+path+ :: Absolute or relative path to .gitlab-ci.yml file
79+
=end
80+
def load_yaml(path)
81+
begin
82+
YAML.load_file(path)
83+
rescue Errno::ENOENT
84+
abort("Failed to load .gitlab-ci.yml")
85+
end
86+
end
87+
88+
=begin
89+
Parse command line options
90+
Returns:
91+
Hash containing keys: {:yaml_file,:url}
92+
=end
93+
def read_args()
94+
options = {}
95+
OptionParser.new do |opt|
96+
opt.on('-f', '--yaml YAML-PATH', 'Path to .gitlab-ci.yml') { |o| options[:yaml_file] = o }
97+
opt.on('-l', '--url GitLab url', 'GitLab API url') { |o| options[:url] = o }
98+
end.parse!
99+
100+
options
101+
end
102+
103+
=begin
104+
Load yaml to send to GitLab API for linting
105+
Display report of linting retrieved from api
106+
Returns:
107+
Exits with 0 upon success and 1 when errors encountered
108+
=end
109+
def main()
110+
# try and parse the arguments
111+
options = read_args()
112+
unless !options.has_key?(:yaml_file) || !options.has_key?(:url)
113+
# try and load the yaml from path
114+
puts "Loading file #{options[:yaml_file]}"
115+
yaml = load_yaml(options[:yaml_file])
116+
117+
# make lint request to api
118+
puts "Making POST request to #{options[:url]}"
119+
response_data=call_api(options[:url], yaml)
120+
121+
# display exit report and raise appropriate exit code
122+
unless !response_data.has_key?("status") || !response_data.has_key?("errors")
123+
exit_report response_data["status"], response_data["errors"]
124+
else
125+
puts "Something went wrong parsing the json response " + response_data
126+
end
127+
else
128+
abort("Missing required arguments yaml_file and url, use -h for usage")
129+
end
130+
end
131+
132+
# start
133+
main

0 commit comments

Comments
 (0)