|
1 | 1 | package com.cloudbees.jenkins; |
2 | 2 |
|
| 3 | +import com.google.common.base.Charsets; |
| 4 | +import com.google.common.base.Function; |
3 | 5 | import hudson.Extension; |
4 | 6 | import hudson.Util; |
5 | 7 | import hudson.console.AnnotatedLargeText; |
| 8 | +import hudson.model.AbstractProject; |
6 | 9 | import hudson.model.Action; |
7 | | -import hudson.model.Hudson; |
8 | | -import hudson.model.Hudson.MasterComputer; |
9 | 10 | import hudson.model.Item; |
10 | | -import hudson.model.AbstractProject; |
11 | 11 | import hudson.model.Project; |
12 | 12 | import hudson.triggers.Trigger; |
13 | 13 | import hudson.triggers.TriggerDescriptor; |
14 | 14 | import hudson.util.FormValidation; |
15 | 15 | import hudson.util.SequentialExecutionQueue; |
16 | 16 | import hudson.util.StreamTaskListener; |
| 17 | +import jenkins.model.Jenkins; |
| 18 | +import jenkins.model.Jenkins.MasterComputer; |
| 19 | +import net.sf.json.JSONObject; |
| 20 | +import org.apache.commons.codec.binary.Base64; |
| 21 | +import org.apache.commons.jelly.XMLOutput; |
| 22 | +import org.jenkinsci.main.modules.instance_identity.InstanceIdentity; |
| 23 | +import org.jenkinsci.plugins.github.webhook.WebhookManager; |
| 24 | +import org.kohsuke.stapler.DataBoundConstructor; |
| 25 | +import org.kohsuke.stapler.QueryParameter; |
| 26 | +import org.kohsuke.stapler.StaplerRequest; |
17 | 27 |
|
| 28 | +import javax.inject.Inject; |
18 | 29 | import java.io.File; |
19 | 30 | import java.io.IOException; |
20 | 31 | import java.io.PrintStream; |
21 | 32 | import java.net.HttpURLConnection; |
22 | 33 | import java.net.MalformedURLException; |
23 | 34 | import java.net.URL; |
24 | | -import java.nio.charset.Charset; |
25 | 35 | import java.security.interfaces.RSAPublicKey; |
26 | 36 | import java.text.DateFormat; |
27 | 37 | import java.util.ArrayList; |
|
33 | 43 | import java.util.logging.Level; |
34 | 44 | import java.util.logging.Logger; |
35 | 45 |
|
36 | | -import jenkins.model.Jenkins; |
37 | | -import net.sf.json.JSONObject; |
38 | | - |
39 | | -import org.apache.commons.codec.binary.Base64; |
40 | | -import org.apache.commons.jelly.XMLOutput; |
41 | | -import org.jenkinsci.main.modules.instance_identity.InstanceIdentity; |
42 | | -import org.kohsuke.github.GHException; |
43 | | -import org.kohsuke.github.GHRepository; |
44 | | -import org.kohsuke.stapler.DataBoundConstructor; |
45 | | -import org.kohsuke.stapler.QueryParameter; |
46 | | -import org.kohsuke.stapler.StaplerRequest; |
47 | | - |
48 | | -import javax.inject.Inject; |
| 46 | +import static org.jenkinsci.plugins.github.util.FluentIterableWrapper.from; |
| 47 | +import static org.jenkinsci.plugins.github.util.JobInfoHelpers.isBuildable; |
| 48 | +import static org.jenkinsci.plugins.github.util.JobInfoHelpers.withTrigger; |
| 49 | +import static org.jenkinsci.plugins.github.webhook.WebhookManager.forHookUrl; |
49 | 50 |
|
50 | 51 | /** |
51 | 52 | * Triggers a build when we receive a GitHub post-commit webhook. |
@@ -149,40 +150,16 @@ public void start(AbstractProject<?, ?> project, boolean newInstance) { |
149 | 150 |
|
150 | 151 | /** |
151 | 152 | * Tries to register hook for current associated job. |
| 153 | + * Do this lazily to avoid blocking the UI thread. |
152 | 154 | * Useful for using from groovy scripts. |
153 | 155 | * @since 1.11.2 |
154 | 156 | */ |
155 | 157 | public void registerHooks() { |
156 | | - // make sure we have hooks installed. do this lazily to avoid blocking the UI thread. |
157 | | - final Collection<GitHubRepositoryName> names = GitHubRepositoryNameContributor.parseAssociatedNames(job); |
158 | | - |
159 | | - getDescriptor().queue.execute(new Runnable() { |
160 | | - public void run() { |
161 | | - LOGGER.log(Level.INFO, "Adding GitHub webhooks for {0}", names); |
162 | | - |
163 | | - for (GitHubRepositoryName name : names) { |
164 | | - for (GHRepository repo : name.resolve()) { |
165 | | - try { |
166 | | - if(createJenkinsHook(repo, getDescriptor().getHookUrl())) { |
167 | | - break; |
168 | | - } |
169 | | - } catch (Throwable e) { |
170 | | - LOGGER.log(Level.WARNING, "Failed to add GitHub webhook for "+name, e); |
171 | | - } |
172 | | - } |
173 | | - } |
174 | | - } |
175 | | - }); |
| 158 | + URL hookUrl = getDescriptor().getHookUrl(); |
| 159 | + Runnable hookRegistrator = forHookUrl(hookUrl).registerFor(job); |
| 160 | + getDescriptor().queue.execute(hookRegistrator); |
176 | 161 | } |
177 | 162 |
|
178 | | - private boolean createJenkinsHook(GHRepository repo, URL url) { |
179 | | - try { |
180 | | - repo.createHook("jenkins", Collections.singletonMap("jenkins_hook_url", url.toExternalForm()), null, true); |
181 | | - return true; |
182 | | - } catch (IOException e) { |
183 | | - throw new GHException("Failed to update jenkins hooks", e); |
184 | | - } |
185 | | - } |
186 | 163 |
|
187 | 164 | @Override |
188 | 165 | public void stop() { |
@@ -233,7 +210,7 @@ public String getLog() throws IOException { |
233 | 210 | * @since 1.350 |
234 | 211 | */ |
235 | 212 | public void writeLogTo(XMLOutput out) throws IOException { |
236 | | - new AnnotatedLargeText<GitHubWebHookPollingAction>(getLogFile(), Charset.defaultCharset(),true,this).writeHtmlTo(0,out.asWriter()); |
| 213 | + new AnnotatedLargeText<GitHubWebHookPollingAction>(getLogFile(), Charsets.UTF_8, true, this).writeHtmlTo(0, out.asWriter()); |
237 | 214 | } |
238 | 215 | } |
239 | 216 |
|
@@ -278,8 +255,14 @@ public void setManageHook(boolean v) { |
278 | 255 | /** |
279 | 256 | * Returns the URL that GitHub should post. |
280 | 257 | */ |
281 | | - public URL getHookUrl() throws MalformedURLException { |
282 | | - return hookUrl!=null ? new URL(hookUrl) : new URL(Hudson.getInstance().getRootUrl()+GitHubWebHook.get().getUrlName()+'/'); |
| 258 | + public URL getHookUrl() { |
| 259 | + try { |
| 260 | + return hookUrl != null |
| 261 | + ? new URL(hookUrl) |
| 262 | + : new URL(Jenkins.getInstance().getRootUrl() + GitHubWebHook.get().getUrlName() + '/'); |
| 263 | + } catch (MalformedURLException e) { |
| 264 | + throw new RuntimeException("Hook url is malformed", e); |
| 265 | + } |
283 | 266 | } |
284 | 267 |
|
285 | 268 | public boolean hasOverrideURL() { |
@@ -337,22 +320,26 @@ public FormValidation doReRegister() { |
337 | 320 | return FormValidation.error("Works only when Jenkins manages hooks"); |
338 | 321 | } |
339 | 322 |
|
340 | | - int triggered = 0; |
341 | | - for (AbstractProject<?,?> job : getJenkinsInstance().getAllItems(AbstractProject.class)) { |
342 | | - if (!job.isBuildable()) { |
343 | | - continue; |
344 | | - } |
| 323 | + List<GitHubPushTrigger> registered = from(getJenkinsInstance().getAllItems(AbstractProject.class)) |
| 324 | + .filter(isBuildable()) |
| 325 | + .filter(withTrigger(GitHubPushTrigger.class)) |
| 326 | + .transform(reRegisterHooks()).toList(); |
345 | 327 |
|
346 | | - GitHubPushTrigger trigger = job.getTrigger(GitHubPushTrigger.class); |
347 | | - if (trigger!=null) { |
| 328 | + |
| 329 | + LOGGER.log(Level.INFO, "Called registerHooks() for {0} jobs", registered.size()); |
| 330 | + return FormValidation.ok("Called re-register hooks for %s jobs", registered.size()); |
| 331 | + } |
| 332 | + |
| 333 | + private Function<AbstractProject, GitHubPushTrigger> reRegisterHooks() { |
| 334 | + return new Function<AbstractProject, GitHubPushTrigger>() { |
| 335 | + @Override |
| 336 | + public GitHubPushTrigger apply(AbstractProject job) { |
| 337 | + GitHubPushTrigger trigger = (GitHubPushTrigger) job.getTrigger(GitHubPushTrigger.class); |
348 | 338 | LOGGER.log(Level.FINE, "Calling registerHooks() for {0}", job.getFullName()); |
349 | 339 | trigger.registerHooks(); |
350 | | - triggered++; |
| 340 | + return trigger; |
351 | 341 | } |
352 | | - } |
353 | | - |
354 | | - LOGGER.log(Level.INFO, "Called registerHooks() for {0} jobs", triggered); |
355 | | - return FormValidation.ok("Called re-register hooks for " + triggered + " jobs"); |
| 342 | + }; |
356 | 343 | } |
357 | 344 |
|
358 | 345 | public static final Jenkins getJenkinsInstance() throws IllegalStateException { |
|
0 commit comments