-
Notifications
You must be signed in to change notification settings - Fork 2
/
.workspace.exs
347 lines (321 loc) · 10.9 KB
/
.workspace.exs
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
154
155
156
157
158
159
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
[
ignore_paths: [".elixir-tools", "artifacts", "cover"],
checks: [
# General package validations
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have a description set",
opts: [
validate: fn project ->
case project.config[:description] do
nil -> {:error, "no :description set"}
description when is_binary(description) -> {:ok, "description set to #{description}"}
other -> {:error, "description must be binary, got: #{inspect(other)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have a maintainer set",
opts: [
validate: fn project ->
config = project.config
package = config[:package] || []
case package[:maintainers] do
value when value in [nil, []] -> {:error, ":maintainers must be set under :package"}
maintainers -> {:ok, "maintainers set to: #{inspect(maintainers)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have licenses set to MIT",
opts: [
validate: fn project ->
config = project.config
package = config[:package] || []
case package[:licenses] do
["MIT"] -> {:ok, "license set to MIT"}
other -> {:error, "invalid licenses, expected [\"MIT\"], got #{inspect(other)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all packages must have the correct GitHub link",
opts: [
validate: fn project ->
config = project.config
package = config[:package] || []
links = package[:links] || %{}
case links["GitHub"] do
"https://github.com/sportradar/elixir-workspace" ->
{:ok, "GitHub link properly set"}
other ->
{:error, "invalid GitHub link: #{inspect(other)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all packages must have the correct Changelog link",
opts: [
validate: fn project ->
config = project.config
package = config[:package] || []
links = package[:links] || %{}
path = Path.relative_to(project.path, project.workspace_path)
expected_url =
"https://github.com/sportradar/elixir-workspace/blob/main/#{path}/CHANGELOG.md"
case links["Changelog"] do
^expected_url ->
{:ok, "Changelog link properly set"}
other ->
{:error, "invalid Changelog link: #{inspect(other)}, expected: #{expected_url}"}
end
end
]
],
# Build paths checks
[
module: Workspace.Checks.ValidateConfigPath,
description: "all projects must have a common dependencies path",
opts: [
config_attribute: :deps_path,
expected_path: "artifacts/deps"
]
],
[
module: Workspace.Checks.ValidateConfigPath,
description: "all projects must have a common build path",
opts: [
config_attribute: :build_path,
expected_path: "artifacts/build"
]
],
# Dependencies checks
[
module: Workspace.Checks.DependenciesVersion,
description: "mono-repo dependencies versions",
opts: [
deps: [
nimble_options: [version: "~> 1.1.1"],
# dev dependencies
dialyxir: [
version: "== 1.4.4",
options: [only: [:dev], runtime: false]
],
ex_doc: [version: "== 0.34.2"],
credo: [version: "== 1.7.8"],
doctor: [version: "== 0.21.0"]
]
]
],
# Documentation related checks
[
module: Workspace.Checks.ValidateConfigPath,
description: "all projects must have a common docs output path",
opts: [
config_attribute: [:docs, :output],
expected_path: fn project -> "artifacts/docs/#{project.app}" end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have only html docs formatters",
opts: [
validate: fn project ->
case project.config[:docs][:formatters] do
["html"] -> {:ok, "only html present in formatters"}
other -> {:error, "expected :docs :formatters to be html, got #{inspect(other)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have a name set",
opts: [
validate: fn project ->
case project.config[:name] do
nil -> {:error, "no :name set"}
name when is_binary(name) -> {:ok, "name set to #{name}"}
other -> {:error, "description must be binary, got: #{inspect(other)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have a valid source_url_pattern",
opts: [
validate: fn project ->
config = project.config
url_pattern = get_in(config, [:docs, :source_url_pattern])
repo_url = "https://github.com/sportradar/elixir-workspace"
app = Keyword.fetch!(config, :app)
version = Keyword.fetch!(config, :version)
expected_url = "#{repo_url}/blob/#{app}/v#{version}/#{app}/%{path}#L%{line}"
if url_pattern == expected_url do
{:ok, ":source_url_pattern correctly set to #{url_pattern}"}
else
{:error,
"invalid :source_url_pattern, expected #{expected_url}, got: #{inspect(url_pattern)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have the same source_url set",
opts: [
validate: fn project ->
expected_url = "https://github.com/sportradar/elixir-workspace"
case project.config[:source_url] do
^expected_url ->
{:ok, ":source_url properly set"}
other ->
{:error, "expected :source_url to be #{expected_url}, got: #{inspect(other)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have the :canonical option properly set",
opts: [
validate: fn project ->
config = project.config
canonical = get_in(config, [:docs, :canonical])
expected = "http://hexdocs.pm/#{config[:app]}"
if canonical == expected do
{:ok, ":canonical properly set to #{canonical}"}
else
{:error,
"invalid :canonical value, expected: #{expected}, got: #{inspect(canonical)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "common files must be in docs extras",
opts: [
validate: fn project ->
config = project.config
extras = get_in(config, [:docs, :extras])
cond do
is_nil(extras[:"README.md"]) ->
{:error, "README.md must be present in docs extras"}
is_nil(extras[:"CHANGELOG.md"]) ->
{:error, "CHANGELOG.md must be present in docs extras"}
is_nil(extras[:LICENSE]) ->
{:error, "LICENSE must be present in docs extras"}
true ->
{:ok, "all extra files are present"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "readme must be the main entry for all docs",
opts: [
validate: fn project ->
case get_in(project.config, [:docs, :main]) do
"readme" -> {:ok, "readme is the main entry point"}
other -> {:error, "expected readme as the main page for docs, got: #{inspect(other)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "CHANGELOG must be in the skip_undefined_reference_warnings_on list",
opts: [
validate: fn project ->
skipped = get_in(project.config, [:docs, :skip_undefined_reference_warnings_on]) || []
case "CHANGELOG.md" in skipped do
true ->
{:ok, "CHANGELOG included in :skip_undefined_reference_warnings_on"}
false ->
{:error,
"CHANGELOG.md should be included under :skip_undefined_reference_warnings_on"}
end
end
]
],
# Testing related checks
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have test_coverage[:output] properly set",
opts: [
validate: fn project ->
config = project.config
coverage_opts = config[:test_coverage] || []
output = coverage_opts[:output]
cond do
is_nil(output) ->
{:error, ":output option not defined under :test_coverage settings"}
not String.ends_with?(output, Atom.to_string(config[:app])) ->
{:error, ":output must point to a folder with the same name as the app name"}
true ->
{:ok, "coverage output set to #{output}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have test_coverage[:export] properly set",
opts: [
validate: fn project ->
config = project.config
coverage_opts = config[:test_coverage] || []
export = coverage_opts[:export]
cond do
export == nil ->
{:error, "export option not defined under :test_coverage settings"}
is_binary(export) and String.starts_with?(export, Atom.to_string(config[:app])) ->
{:ok, "output properly set to #{export}"}
true ->
{:error,
"invalid value for output, it should be a binary starting with #{config[:app]}, got: #{inspect(export)}"}
end
end
]
],
[
module: Workspace.Checks.ValidateProject,
description: "all projects must have a minimum coverage threshold of 95",
opts: [
validate: fn project ->
config = project.config
coverage_opts = config[:test_coverage] || []
threshold = coverage_opts[:threshold] || 0
if threshold >= 95 do
{:ok, "threshold is at #{threshold}%"}
else
{:error, "threshold must be at least 98, got: #{threshold}"}
end
end
]
]
],
test_coverage: [
allow_failure: [:workspace],
threshold: 98,
warning_threshold: 99,
exporters: [
lcov: fn workspace, coverage_stats ->
Workspace.Coverage.LCOV.export(workspace, coverage_stats,
output_path: "artifacts/coverage"
)
end
]
]
]