1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
# frozen_string_literal: true
return if Rails.env.production?
require 'graphql/rake_task'
namespace :gitlab do
OUTPUT_DIR = Rails.root.join("doc/api/graphql/reference")
TEMP_SCHEMA_DIR = Rails.root.join('tmp/tests/graphql')
TEMPLATES_DIR = 'lib/gitlab/graphql/docs/templates/'
# Make all feature flags enabled so that all feature flag
# controlled fields are considered visible and are output.
# Also avoids pipeline failures in case developer
# dumps schema with flags disabled locally before pushing
task enable_feature_flags: :environment do
class Feature
def self.enabled?(*args)
true
end
end
end
# Defines tasks for dumping the GraphQL schema:
# - gitlab:graphql:schema:dump
# - gitlab:graphql:schema:idl
# - gitlab:graphql:schema:json
GraphQL::RakeTask.new(
schema_name: 'GitlabSchema',
dependencies: [:environment, :enable_feature_flags],
directory: TEMP_SCHEMA_DIR,
idl_outfile: "gitlab_schema.graphql",
json_outfile: "gitlab_schema.json"
)
namespace :graphql do
desc 'GitLab | GraphQL | Analyze queries'
task analyze: [:environment, :enable_feature_flags] do |t, args|
queries = if args.to_a.present?
args.to_a.flat_map { |path| Gitlab::Graphql::Queries.find(path) }
else
Gitlab::Graphql::Queries.all
end
queries.each do |defn|
$stdout.puts defn.file
summary, errs = defn.validate(GitlabSchema)
if summary == :client_query
$stdout.puts " - client query"
elsif errs.present?
$stdout.puts " - invalid query".color(:red)
else
complexity = defn.complexity(GitlabSchema)
color = case complexity
when 0..GitlabSchema::DEFAULT_MAX_COMPLEXITY
:green
when GitlabSchema::DEFAULT_MAX_COMPLEXITY..GitlabSchema::AUTHENTICATED_COMPLEXITY
:yellow
when GitlabSchema::AUTHENTICATED_COMPLEXITY..GitlabSchema::ADMIN_COMPLEXITY
:orange
else
:red
end
$stdout.puts " - complexity: #{complexity}".color(color)
end
$stdout.puts ""
end
end
desc 'GitLab | GraphQL | Validate queries'
task validate: [:environment, :enable_feature_flags] do |t, args|
queries = if args.to_a.present?
args.to_a.flat_map { |path| Gitlab::Graphql::Queries.find(path) }
else
Gitlab::Graphql::Queries.all
end
failed = queries.flat_map do |defn|
summary, errs = defn.validate(GitlabSchema)
case summary
when :client_query
warn("SKIP #{defn.file}: client query")
else
warn("#{'OK'.color(:green)} #{defn.file}") if errs.empty?
errs.each do |err|
warn(<<~MSG)
#{'ERROR'.color(:red)} #{defn.file}: #{err.message} (at #{err.path.join('.')})
MSG
end
end
errs.empty? ? [] : [defn.file]
end
if failed.present?
format_output(
"#{failed.count} GraphQL #{'query'.pluralize(failed.count)} out of #{queries.count} failed validation:",
*failed.map do |name|
known_failure = Gitlab::Graphql::Queries.known_failure?(name)
"- #{name}" + (known_failure ? ' (known failure)' : '')
end
)
abort unless failed.all? { |name| Gitlab::Graphql::Queries.known_failure?(name) }
end
end
desc 'GitLab | GraphQL | Generate GraphQL docs'
task compile_docs: [:environment, :enable_feature_flags] do
renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema, render_options)
renderer.write
puts "Documentation compiled."
end
desc 'GitLab | GraphQL | Check if GraphQL docs are up to date'
task check_docs: [:environment, :enable_feature_flags] do
renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema, render_options)
doc = File.read(Rails.root.join(OUTPUT_DIR, 'index.md'))
if doc == renderer.contents
puts "GraphQL documentation is up to date"
else
format_output('GraphQL documentation is outdated! Please update it by running `bundle exec rake gitlab:graphql:compile_docs`.')
abort
end
end
desc 'GitLab | GraphQL | Update GraphQL docs and schema'
task update_all: [:compile_docs, 'schema:dump']
end
end
def render_options
{
output_dir: OUTPUT_DIR,
template: Rails.root.join(TEMPLATES_DIR, 'default.md.haml')
}
end
def format_output(*strs)
heading = '#' * 10
puts heading
puts '#'
strs.each { |str| puts "# #{str}" }
puts '#'
puts heading
end
|