Skip to content

Commit a57f83f

Browse files
somiljain2006timja
andauthored
Update ConfigurationAsCode category and exception handling (#2830)
Co-authored-by: Tim Jacomb <[email protected]>
1 parent 5212045 commit a57f83f

5 files changed

Lines changed: 76 additions & 35 deletions

File tree

plugin/src/main/java/io/jenkins/plugins/casc/ConfigurationAsCode.java

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,10 @@ public String getDescription() {
143143
return "Reload your configuration or update configuration source.";
144144
}
145145

146-
/**
147-
* Name of the category for this management link.
148-
* TODO: Use getCategory when core requirement is greater or equal to 2.226
149-
*/
150-
public @NonNull String getCategoryName() {
151-
return "CONFIGURATION";
146+
@NonNull
147+
@Override
148+
public Category getCategory() {
149+
return Category.CONFIGURATION;
152150
}
153151

154152
@NonNull
@@ -228,7 +226,8 @@ public void doReplace(StaplerRequest2 request, StaplerResponse2 response) throws
228226
candidateSources.add(candidateSource);
229227
} else {
230228
LOGGER.log(Level.WARNING, "Source {0} could not be applied", candidateSource);
231-
// todo: show message in UI
229+
throw new ConfiguratorException(
230+
"Source " + candidateSource + " could not be applied or does not exist.");
232231
}
233232
}
234233
if (!candidateSources.isEmpty()) {
@@ -244,7 +243,8 @@ public void doReplace(StaplerRequest2 request, StaplerResponse2 response) throws
244243
LOGGER.log(Level.FINE, "Replace configuration with: " + normalizedSource);
245244
} else {
246245
LOGGER.log(Level.WARNING, "Provided sources could not be applied");
247-
// todo: show message in UI
246+
throw new ConfiguratorException(
247+
"Provided sources could not be applied. Please check the syntax and validity of the provided configuration.");
248248
}
249249
} else {
250250
LOGGER.log(Level.FINE, "No such source exists, applying default");
@@ -453,7 +453,12 @@ public List<String> getBundledCasCURIs() {
453453
URL bundled = servletContext.getResource(cascItem);
454454
if (bundled != null && matcher.matches(new File(bundled.getPath()).toPath())) {
455455
res.add(bundled.toString());
456-
} // TODO: else do some handling?
456+
} else if (bundled != null) {
457+
LOGGER.log(
458+
Level.FINE,
459+
"Skipped bundled resource {0} as it does not match the YAML pattern.",
460+
bundled.getPath());
461+
}
457462
} catch (IOException e) {
458463
LOGGER.log(Level.WARNING, "Failed to execute " + res, e);
459464
}
@@ -569,23 +574,7 @@ public void doViewExport(StaplerRequest2 req, StaplerResponse2 res) throws Excep
569574
ByteArrayOutputStream out = new ByteArrayOutputStream();
570575
export(out);
571576

572-
req.setAttribute("viewExport", new ManagementLink() {
573-
@Override
574-
public String getIconFileName() {
575-
return "";
576-
}
577-
578-
// TODO - FIX - EXTREMELY HACKY - couldn't expose a public method for some reason
579-
@Override
580-
public String getUrlName() {
581-
return out.toString(StandardCharsets.UTF_8);
582-
}
583-
584-
@Override
585-
public String getDisplayName() {
586-
return "Export configuration";
587-
}
588-
});
577+
req.setAttribute("exportedYaml", out.toString(StandardCharsets.UTF_8));
589578
req.getView(this, "viewExport.jelly").forward(req, res);
590579
}
591580

plugin/src/main/resources/io/jenkins/plugins/casc/ConfigurationAsCode/viewExport.jelly

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
xmlns:f="/lib/form">
44
<j:set var="header">
55
<l:view>
6-
<l:app-bar title="${viewExport.displayName}">
6+
<l:app-bar title="${%Export configuration}">
77
<f:form method="post" action="export" name="export">
88
<f:submit icon="symbol-download" primary="false" name="export" value="${%Download}"/>
99
</f:form>
1010
</l:app-bar>
1111
</l:view>
1212
</j:set>
1313

14-
<l:settings-subpage includeBreadcrumb="true" header="${header}" managementLink="${viewExport}" noDefer="true">
14+
<l:settings-subpage includeBreadcrumb="true" header="${header}" title="${%Export configuration}">
1515
<st:adjunct includes="io.jenkins.plugins.casc.assets.viewExport" />
1616

1717
<div class="jenkins-alert jenkins-alert-info">
@@ -20,7 +20,7 @@
2020

2121
<p:prism configuration="${it.prismConfiguration}" />
2222
<pre>
23-
<code class="language-yaml">${viewExport.urlName}</code>
23+
<code class="language-yaml">${exportedYaml}</code>
2424
</pre>
2525
</l:settings-subpage>
2626
</j:jelly>

plugin/src/test/java/io/jenkins/plugins/casc/ConfigurationAsCodeApiTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
import static org.hamcrest.Matchers.is;
66

77
import java.net.URL;
8+
import java.nio.file.Files;
9+
import java.nio.file.Path;
10+
import java.util.List;
811
import jenkins.model.Jenkins;
912
import org.htmlunit.HttpMethod;
1013
import org.htmlunit.WebRequest;
1114
import org.htmlunit.WebResponse;
15+
import org.htmlunit.util.NameValuePair;
1216
import org.junit.Rule;
1317
import org.junit.Test;
1418
import org.jvnet.hudson.test.JenkinsRule;
@@ -159,4 +163,26 @@ public void testDoConfigure_ValidYaml_NoChanges() throws Exception {
159163
assertThat(j.jenkins.getSystemMessage(), is("Idempotency Test"));
160164
}
161165
}
166+
167+
@Test
168+
public void testDoReplace_ValidSource() throws Exception {
169+
configureAdminSecurity();
170+
171+
Path configFile = Files.createTempFile("valid", ".yaml");
172+
Files.writeString(configFile, "jenkins:\n systemMessage: 'Hello Replace'");
173+
174+
try (JenkinsRule.WebClient wc = j.createWebClient().withBasicApiToken(ADMIN)) {
175+
wc.setThrowExceptionOnFailingStatusCode(false);
176+
177+
WebRequest request =
178+
new WebRequest(new URL(j.getURL(), "manage/configuration-as-code/replace"), HttpMethod.POST);
179+
180+
request.setRequestParameters(List.of(new NameValuePair("_.newSource", configFile.toString())));
181+
182+
WebResponse response = wc.getPage(request).getWebResponse();
183+
184+
assertThat(response.getStatusCode(), is(200));
185+
assertThat(j.jenkins.getSystemMessage(), is("Hello Replace"));
186+
}
187+
}
162188
}

plugin/src/test/java/io/jenkins/plugins/casc/ErrorPageTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.jenkins.plugins.casc;
22

3+
import static jenkins.model.Jenkins.ADMINISTER;
34
import static org.hamcrest.MatcherAssert.assertThat;
45
import static org.hamcrest.Matchers.containsString;
56

@@ -16,6 +17,7 @@
1617
import org.junit.jupiter.api.io.TempDir;
1718
import org.jvnet.hudson.test.JenkinsRule;
1819
import org.jvnet.hudson.test.JenkinsRule.WebClient;
20+
import org.jvnet.hudson.test.MockAuthorizationStrategy;
1921
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
2022

2123
@WithJenkins
@@ -87,4 +89,34 @@ void noImplementationFoundForSymbol() throws Exception {
8789
assertThat(pageContent, containsString("Attribute was:"));
8890
assertThat(pageContent, containsString("unknown"));
8991
}
92+
93+
@Test
94+
void replaceWithInvalidSource() throws Exception {
95+
String pageContent = replaceConfiguration();
96+
97+
assertThat(
98+
pageContent, containsString("Source non-existent-file.yaml could not be applied or does not exist."));
99+
}
100+
101+
private String replaceConfiguration() throws Exception {
102+
r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
103+
r.jenkins.setAuthorizationStrategy(
104+
new MockAuthorizationStrategy().grant(ADMINISTER).everywhere().to("admin"));
105+
106+
try (WebClient webClient = r.createWebClient().withThrowExceptionOnFailingStatusCode(false)) {
107+
webClient.login("admin", "admin");
108+
109+
HtmlPage htmlPage = webClient.goTo("manage/configuration-as-code/");
110+
111+
HtmlButton button = (HtmlButton) htmlPage.getElementById("btn-open-apply-configuration");
112+
HtmlElementUtil.click(button);
113+
114+
HtmlForm replaceForm = htmlPage.getFormByName("replace");
115+
replaceForm.getInputByName("_.newSource").setValue("non-existent-file.yaml");
116+
117+
HtmlPage submit = r.submit(replaceForm);
118+
119+
return submit.asNormalizedText();
120+
}
121+
}
90122
}

test-harness/src/test/java/io/jenkins/plugins/casc/ConfigurationAsCodeTest.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,6 @@ void testHtmlDocStringRetrieval(JenkinsConfiguredWithCodeRule j) throws Exceptio
340340
assertEquals(expectedDocString, actualDocString);
341341
}
342342

343-
@Test
344-
void configurationCategory(JenkinsConfiguredWithCodeRule j) {
345-
ConfigurationAsCode configurationAsCode = ConfigurationAsCode.get();
346-
assertThat(configurationAsCode.getCategoryName(), is("CONFIGURATION"));
347-
}
348-
349343
private static File newFolder(File root, String... subDirs) throws IOException {
350344
String subFolder = String.join("/", subDirs);
351345
File result = new File(root, subFolder);

0 commit comments

Comments
 (0)