forked from jenkinsci/configuration-as-code-plugin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUtil.java
327 lines (302 loc) · 12.7 KB
/
Util.java
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
package io.jenkins.plugins.casc.misc;
import static io.jenkins.plugins.casc.ConfigurationAsCode.serializeYamlNode;
import static io.jenkins.plugins.casc.SchemaGeneration.generateSchema;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import hudson.ExtensionList;
import io.jenkins.plugins.casc.ConfigurationAsCode;
import io.jenkins.plugins.casc.ConfigurationContext;
import io.jenkins.plugins.casc.core.JenkinsConfigurator;
import io.jenkins.plugins.casc.impl.configurators.GlobalConfigurationCategoryConfigurator;
import io.jenkins.plugins.casc.model.CNode;
import io.jenkins.plugins.casc.model.Mapping;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UncheckedIOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.model.GlobalConfigurationCategory;
import jenkins.tools.ToolConfigurationCategory;
import org.everit.json.schema.Schema;
import org.everit.json.schema.ValidationException;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.LoggerRule;
import org.yaml.snakeyaml.nodes.Node;
public class Util {
private static final Logger LOGGER = Logger.getLogger(Util.class.getName());
private static final String failureMessage = "The YAML file provided for this schema is invalid";
/**
* Gets the Jenkins configurator.
*
* @return the Jenkins configurator
*/
public static JenkinsConfigurator getJenkinsConfigurator() {
return ExtensionList.lookup(JenkinsConfigurator.class).get(0);
}
/**
* Gets the "jenkins" root mapping.
* <p>
* Example usage:
* <pre>{@code
* ConfiguratorRegistry registry = ConfiguratorRegistry.get();
* ConfigurationContext context = new ConfigurationContext(registry);
* CNode configNode = getJenkinsRoot(context).get("nodes");}</pre>
*
* @param context the configuration context
* @return the "jenkins" root mapping
* @throws Exception something's not right...
*/
public static Mapping getJenkinsRoot(ConfigurationContext context) throws Exception {
JenkinsConfigurator root = getJenkinsConfigurator();
return Objects.requireNonNull(root.describe(root.getTargetComponent(context), context))
.asMapping();
}
/**
* Gets the "unclassified" root mapping.
* <p>
* Example usage:
* <pre>{@code
* ConfiguratorRegistry registry = ConfiguratorRegistry.get();
* ConfigurationContext context = new ConfigurationContext(registry);
* CNode configNode = getUnclassifiedRoot(context).get("my-plugin-attribute");}</pre>
*
* @param context the configuration context
* @return the "unclassified" root mapping
* @throws Exception something's not right...
*/
public static Mapping getUnclassifiedRoot(ConfigurationContext context) throws Exception {
GlobalConfigurationCategory.Unclassified unclassified = ExtensionList.lookup(
GlobalConfigurationCategory.Unclassified.class)
.get(0);
GlobalConfigurationCategoryConfigurator unclassifiedConfigurator =
new GlobalConfigurationCategoryConfigurator(unclassified);
return Objects.requireNonNull(unclassifiedConfigurator.describe(
unclassifiedConfigurator.getTargetComponent(context), context))
.asMapping();
}
/**
* Gets the "security" root mapping.
* <p>
* Example usage:
* <pre>{@code
* ConfiguratorRegistry registry = ConfiguratorRegistry.get();
* ConfigurationContext context = new ConfigurationContext(registry);
* CNode configNode = getSecurityRoot(context).get("GlobalJobDslSecurityConfiguration");}</pre>
*
* @param context the configuration context
* @return the "security" root mapping
* @throws Exception something's not right...
*/
public static Mapping getSecurityRoot(ConfigurationContext context) throws Exception {
GlobalConfigurationCategory.Security security =
ExtensionList.lookup(GlobalConfigurationCategory.Security.class).get(0);
GlobalConfigurationCategoryConfigurator securityConfigurator =
new GlobalConfigurationCategoryConfigurator(security);
return Objects.requireNonNull(
securityConfigurator.describe(securityConfigurator.getTargetComponent(context), context))
.asMapping();
}
/**
* Gets the "tool" root mapping.
* <p>
* Example usage:
* <pre>{@code
* ConfiguratorRegistry registry = ConfiguratorRegistry.get();
* ConfigurationContext context = new ConfigurationContext(registry);
* CNode configNode = getToolRoot(context).get("git");}</pre>
*
* @param context the configuration context
* @return the "tool" root mapping
* @throws Exception something's not right...
*/
public static Mapping getToolRoot(ConfigurationContext context) throws Exception {
ToolConfigurationCategory category =
ExtensionList.lookup(ToolConfigurationCategory.class).get(0);
GlobalConfigurationCategoryConfigurator configurator = new GlobalConfigurationCategoryConfigurator(category);
return Objects.requireNonNull(configurator.describe(configurator.getTargetComponent(context), context))
.asMapping();
}
/**
* Converts a given {@code CNode} into a string.
* <p>
* Example usage:
* <pre>{@code
* ConfiguratorRegistry registry = ConfiguratorRegistry.get();
* ConfigurationContext context = new ConfigurationContext(registry);
* CNode yourAttribute = getUnclassifiedRoot(context).get("<your-attribute>");
*
* String exported = toYamlString(yourAttribute);}</pre>
*
* @param rootNode the {@code CNode} to convert to a string
* @return a YAML string
* @throws IOException if exporting to YAML fails
*/
public static String toYamlString(CNode rootNode) throws IOException {
Node yamlRoot = ConfigurationAsCode.get().toYaml(rootNode);
StringWriter buffer = new StringWriter();
serializeYamlNode(yamlRoot, buffer);
return buffer.toString();
}
/**
* Reads a resource from the classpath to use in asserting expected export content.
* <p>
* The resource is expected to be UTF-8 encoded.
* <p>
* Example usage:
* <pre>{@code
* toStringFromYamlFile(this, "expected-output.yml");}</pre>
*
* @param clazz pass in {@code this}
* @param resourcePath the file name to read, should be in the same package as your test class in resources
* @return the string content of the file
* @throws URISyntaxException if an invalid URI is passed.
*/
public static String toStringFromYamlFile(Object clazz, String resourcePath) throws URISyntaxException {
try {
URL resource = clazz.getClass().getResource(resourcePath);
if (resource == null) {
throw new FileNotFoundException("Couldn't find file: " + resourcePath);
}
byte[] bytes = Files.readAllBytes(Paths.get(resource.toURI()));
return new String(bytes, StandardCharsets.UTF_8).replaceAll("\r\n?", "\n");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* Checks whether {@link LoggerRule} has not recorded the message.
* @param logging Logger rule
* @param unexpectedText Text to check
* @since 1.25
*/
public static void assertNotInLog(LoggerRule logging, String unexpectedText) {
assertFalse(
"The log should not contain '" + unexpectedText + "'",
logging.getMessages().stream().anyMatch(m -> m.contains(unexpectedText)));
}
/**
* Checks whether {@link LogRecorder} has not recorded the message.
* @param logging Logger rule
* @param unexpectedText Text to check
*/
public static void assertNotInLog(LogRecorder logging, String unexpectedText) {
assertFalse(
"The log should not contain '" + unexpectedText + "'",
logging.getMessages().stream().anyMatch(m -> m.contains(unexpectedText)));
}
/**
* Checks whether {@link LoggerRule} has recorded the message.
* @param logging Logger rule
* @param expectedText Text to check
* @since 1.25
*/
public static void assertLogContains(LoggerRule logging, String expectedText) {
assertTrue(
"The log should contain '" + expectedText + "'",
logging.getMessages().stream().anyMatch(m -> m.contains(expectedText)));
}
/**
* Checks whether {@link LogRecorder} has recorded the message.
* @param logging Logger rule
* @param expectedText Text to check
*/
public static void assertLogContains(LogRecorder logging, String expectedText) {
assertTrue(
"The log should contain '" + expectedText + "'",
logging.getMessages().stream().anyMatch(m -> m.contains(expectedText)));
}
/**
* <p>Converts a given yamlString into a JsonString.</p>
* <p>Example Usage:</p>
* <pre>{@code
* String jsonString = convertToJson(yourYamlString);}
* </pre>
* @param yamlString the yaml to convert
* @return the json conversion of the yaml string.
*/
public static String convertToJson(String yamlString) {
try {
ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
Object obj = yamlReader.readValue(yamlString, Object.class);
ObjectMapper jsonWriter = new ObjectMapper();
return jsonWriter.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new UncheckedIOException(e);
}
}
/**
* Retrieves the JSON schema for the running jenkins instance.
* <p>Example Usage:</p>
* <pre>{@code
* Schema jsonSchema = returnSchema();}
* </pre>
*
* @return the schema for the current jenkins instance
*/
public static Schema returnSchema() {
JSONObject schemaObject = generateSchema();
JSONObject jsonSchema = new JSONObject(new JSONTokener(schemaObject.toString()));
return SchemaLoader.load(jsonSchema);
}
/**
* Validates a given jsonObject against the schema generated for the current live jenkins
* instance.
*
* <p>Example Usage:</p>
* <pre>{@code
* assertThat(validateSchema(convertYamlFileToJson(this, "invalidSchemaConfig.yml")),
* contains("#/jenkins/numExecutors: expected type: Number, found: String"));
* }</pre>
*
* <pre>{@code
* assertThat(validateSchema(convertYamlFileToJson(this, "validConfig.yml")),
* empty());
* }</pre>
*
* @param jsonSubject the json object that needs to be validated
* @return a list of validation errors, empty list if no errors
*/
public static List<String> validateSchema(JSONObject jsonSubject) {
try {
returnSchema().validate(jsonSubject);
} catch (ValidationException e) {
return e.getAllMessages();
} catch (Exception ie) {
LOGGER.log(Level.WARNING, failureMessage, ie);
return singletonList("Exception during test" + ie.getMessage());
}
return emptyList();
}
/**
* Converts a YAML file into a json object
* <p>Example Usage:</p>
* <pre>{@code
* JSONObject jsonObject = convertYamlFileToJson(this, "filename");}
* </pre>
*
* @param clazz the class used for loading resources, normally you want to pass 'this'
* @param yamlFileName the name of the yaml file that needs to be converted
* @return JSONObject pertaining to that yaml file.
* @throws URISyntaxException if an invalid URI is passed.
*/
public static JSONObject convertYamlFileToJson(Object clazz, String yamlFileName) throws URISyntaxException {
String yamlStringContents = toStringFromYamlFile(clazz, yamlFileName);
return new JSONObject(new JSONTokener(convertToJson(yamlStringContents)));
}
}