package com.cloudbees.jenkins; import hudson.Extension; import hudson.model.Item; import hudson.model.PeriodicWork; import jenkins.model.Jenkins; import org.jenkinsci.plugins.github.GitHubPlugin; import org.jenkinsci.plugins.github.webhook.WebhookManager; import java.net.URL; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import static org.jenkinsci.plugins.github.util.FluentIterableWrapper.from; import static org.jenkinsci.plugins.github.util.JobInfoHelpers.associatedNames; import static org.jenkinsci.plugins.github.util.JobInfoHelpers.isAlive; /** * Removes post-commit hooks from repositories that we no longer care. * * This runs periodically in a delayed fashion to avoid hitting GitHub too often. * * @author Kohsuke Kawaguchi */ @Extension public class Cleaner extends PeriodicWork { /** * Queue contains repo names prepared to cleanup. * After configure method on job, trigger calls {@link #onStop(Item)} * which converts to repo names with help of contributors. * * This queue is thread-safe, so any thread can write or * fetch names to this queue without additional sync */ private final Queue<GitHubRepositoryName> cleanQueue = new ConcurrentLinkedQueue<GitHubRepositoryName>(); /** * Called when a {@link GitHubPushTrigger} is about to be removed. */ /* package */ void onStop(Item item) { cleanQueue.addAll(GitHubRepositoryNameContributor.parseAssociatedNames(item)); } @Override public long getRecurrencePeriod() { return TimeUnit.MINUTES.toMillis(3); } /** * Each run this work fetches alive repo names (which has trigger for it) * then if names queue is not empty (any job was reconfigured with GH trigger change), * next name passed to {@link WebhookManager} with list of active names to check and unregister old hooks */ @Override protected void doRun() throws Exception { if (!GitHubPlugin.configuration().isManageHooks()) { return; } URL url = GitHubPlugin.configuration().getHookUrl(); List<Item> items = Jenkins.getInstance().getAllItems(Item.class); List<GitHubRepositoryName> aliveRepos = from(items) .filter(isAlive()) // live repos .transformAndConcat(associatedNames()).toList(); while (!cleanQueue.isEmpty()) { GitHubRepositoryName name = cleanQueue.poll(); WebhookManager.forHookUrl(url).unregisterFor(name, aliveRepos); } } public static Cleaner get() { return PeriodicWork.all().get(Cleaner.class); } }