Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JENKINS-60738] Fix global configuration submission from UI #347

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import hudson.BulkChange;
import hudson.Extension;
import hudson.Util;
import hudson.XmlFile;
Expand Down Expand Up @@ -190,17 +191,35 @@ protected XmlFile getConfigFile() {

@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
hookSecretConfigs = null; // form binding might omit empty lists
try {
req.bindJSON(this, json);
BulkChange bc = new BulkChange(this);
try {
if (json.has("configs")) {
setConfigs(req.bindJSONToList(GitHubServerConfig.class, json.get("configs")));
} else {
setConfigs(Collections.emptyList());
}
if (json.has("hookSecretConfigs")) {
setHookSecretConfigs(req.bindJSONToList(HookSecretConfig.class, json.get("hookSecretConfigs")));
} else {
setHookSecretConfigs(Collections.emptyList());
}
if (json.optBoolean("isOverrideHookUrl", false) && (json.has("hookUrl"))) {
setHookUrl(json.optString("hookUrl"));
} else {
setHookUrl(null);
}
req.bindJSON(this, json);
clearRedundantCaches(configs);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than this method call, the whole configure method should not even need to be overridden.

Copy link
Contributor Author

@Dohbedoh Dohbedoh Jun 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only way I found to simplify the data-binding and just do a req.bindJson is to change the signature of public URL getHookUrl() to public String getHookUrl(). That could be a breaking change. Example at 77cfb02.

So not sure if that would be acceptable ? cc @KostyaSha

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better ask @jglick i forgot databinding nuances

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That could be a breaking change. … So not sure if that would be acceptable ?

https://github.com/search?q=org%3Ajenkinsci%20getHookUrl&type=code does not look like it is used from other plugins.

} finally {
bc.commit();
}
} catch (Exception e) {
LOGGER.debug("Problem while submitting form for GitHub Plugin ({})", e.getMessage(), e);
LOGGER.trace("GH form data: {}", json.toString());
throw new FormException(
format("Malformed GitHub Plugin configuration (%s)", e.getMessage()), e, "github-configuration");
}
save();
clearRedundantCaches(configs);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ f.section(title: descriptor.displayName) {
f.entry(title: _("Override Hook URL")) {
g.blockWrapper {
f.optionalBlock(title: _("Specify another hook URL for GitHub configuration"),
name: "isOverrideHookUrl",
inline: true,
checked: instance.isOverrideHookUrl()) {
f.entry(field: "hookUrl") {
f.textbox(checkMethod: "post")
f.textbox(checkMethod: "post", name: "hookUrl")
}
}
}
Comment on lines 27 to 37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example all of this should just be like

<f:entry field="hookUrl">
  <f:textbox label="Alternate hook URL for GitHub configuration"/>
</f:entry>

which may be blank.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see. Remove all the optional block that is not necessary.. Yeah sounds good to me I can test this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be more work for sure. The usual problem with this sort of fix is retaining compatibility for both XML settings and JCasC. Sometimes hacking up the JSON processing in the GUI logic is the only option since refactoring to a simpler structure would break something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the thing that bother me is the type URL of the hookUrl... Because of that type, the value cannot actually be blank :( :

java.net.MalformedURLException: no protocol: 
	at java.base/java.net.URL.<init>(URL.java:645)
	at java.base/java.net.URL.<init>(URL.java:541)
	at java.base/java.net.URL.<init>(URL.java:488)
	at org.kohsuke.stapler.Stapler$3.convert(Stapler.java:1141)
Caused: org.apache.commons.beanutils.ConversionException: no protocol: 

So it is not that simple to "reset" the hook URL because of the binding.. I thought about changing the type from URL to String but the existing public getter might be a problem: https://github.com/jenkinsci/github-plugin/blob/master/src/main/java/org/jenkinsci/plugins/github/config/GitHubPluginConfig.java#L131-L141

Changing its signature could be a breaking change. Though it does not seem to be used outside the scope of that plugin repo: https://github.com/search?ref=simplesearch&type=code&q=user%3Ajenkinsci++getHookUrl.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW use permalinks for better display:

/**
* @return hook url used as endpoint to search and write auto-managed hooks in GH
* @throws GHPluginConfigException if default jenkins url is malformed
*/
public URL getHookUrl() throws GHPluginConfigException {
if (hookUrl != null) {
return hookUrl;
} else {
return constructDefaultUrl();
}
}

Expand Down
24 changes: 5 additions & 19 deletions src/test/java/com/cloudbees/jenkins/GlobalConfigSubmitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.htmlunit.html.HtmlForm;
import org.htmlunit.html.HtmlPage;
import org.jenkinsci.plugins.github.GitHubPlugin;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
Expand All @@ -14,17 +13,17 @@

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;

/**
* Test Class for {@link GitHubPushTrigger}.
*
* @author Seiji Sogabe
*/
@Ignore("Have troubles with memory consumption")
public class GlobalConfigSubmitTest {

public static final String OVERRIDE_HOOK_URL_CHECKBOX = "_.isOverrideHookUrl";
public static final String HOOK_URL_INPUT = "_.hookUrl";
public static final String OVERRIDE_HOOK_URL_CHECKBOX = "isOverrideHookUrl";
public static final String HOOK_URL_INPUT = "hookUrl";

private static final String WEBHOOK_URL = "http://jenkinsci.example.com/jenkins/github-webhook/";

Expand All @@ -43,7 +42,7 @@ public void shouldSetHookUrl() throws Exception {
}

@Test
public void shouldNotSetHookUrl() throws Exception {
public void shouldResetHookUrlIfNotChecked() throws Exception {
GitHubPlugin.configuration().setHookUrl(WEBHOOK_URL);

HtmlForm form = globalConfig();
Expand All @@ -52,20 +51,7 @@ public void shouldNotSetHookUrl() throws Exception {
form.getInputByName(HOOK_URL_INPUT).setValue("http://foo");
jenkins.submit(form);

assertThat(GitHubPlugin.configuration().getHookUrl(), equalTo(new URL(WEBHOOK_URL)));
}

@Test
public void shouldNotOverrideAPreviousHookUrlIfNotChecked() throws Exception {
GitHubPlugin.configuration().setHookUrl(WEBHOOK_URL);

HtmlForm form = globalConfig();

form.getInputByName(OVERRIDE_HOOK_URL_CHECKBOX).setChecked(false);
form.getInputByName(HOOK_URL_INPUT).setValue("");
jenkins.submit(form);

assertThat(GitHubPlugin.configuration().getHookUrl(), equalTo(new URL(WEBHOOK_URL)));
assertThat(GitHubPlugin.configuration().getHookUrl().toString(), startsWith(jenkins.jenkins.getRootUrl()));
}

public HtmlForm globalConfig() throws IOException, SAXException {
Expand Down