package io.jenkins.plugins.gitlabbranchsource; import com.damnhandy.uri.template.UriTemplate; import com.damnhandy.uri.template.UriTemplateBuilder; import io.jenkins.plugins.gitlabserverconfig.credentials.PersonalAccessToken; import io.jenkins.plugins.gitlabserverconfig.servers.GitLabServer; import io.jenkins.plugins.gitlabserverconfig.servers.GitLabServers; import java.net.MalformedURLException; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.Jenkins; import jenkins.scm.api.SCMNavigatorOwner; import org.apache.commons.lang.StringUtils; import org.gitlab4j.api.GitLabApi; import org.gitlab4j.api.GitLabApiException; import org.gitlab4j.api.models.ProjectHook; import org.gitlab4j.api.models.SystemHook; public class GitLabHookCreator { public static final Logger LOGGER = Logger.getLogger(GitLabHookCreator.class.getName()); public static void register(SCMNavigatorOwner owner, GitLabSCMNavigator navigator, GitLabHookRegistration systemhookMode) { PersonalAccessToken credentials; GitLabServer server = GitLabServers.get().findServer(navigator.getServerName()); if (server == null) { return; } switch (systemhookMode) { case DISABLE: return; case SYSTEM: if (!server.isManageSystemHooks()) { return; } credentials = server.getCredentials(); if (credentials == null) { LOGGER.log(Level.WARNING, "No System credentials added, cannot create system hook"); } break; case ITEM: credentials = navigator.credentials(owner); if (credentials == null) { LOGGER.log(Level.WARNING, "No Item credentials added, cannot create system hook"); } break; default: return; } // add system hooks if (credentials != null) { createSystemHookWhenMissing(server, credentials); } } public static void register(GitLabSCMSource source, GitLabHookRegistration webhookMode, GitLabHookRegistration systemhookMode) { PersonalAccessToken credentials = null; GitLabServer server = GitLabServers.get().findServer(source.getServerName()); if (server == null) { return; } switch (webhookMode) { case DISABLE: break; case SYSTEM: if (!server.isManageWebHooks()) { break; } credentials = server.getCredentials(); if (credentials == null) { LOGGER.log(Level.WARNING, "No System credentials added, cannot create web hook"); } break; case ITEM: credentials = source.credentials(); if (credentials == null) { LOGGER.log(Level.WARNING, "No Item credentials added, cannot create web hook"); } break; default: return; } String hookUrl = getHookUrl(server, true); String secretToken = server.getSecretToken().getPlainText(); if (hookUrl.equals("")) { return; } if (credentials != null) { try { GitLabApi gitLabApi = new GitLabApi(server.getServerUrl(), credentials.getToken().getPlainText()); createWebHookWhenMissing(gitLabApi, source.getProjectPath(), hookUrl, secretToken); } catch (GitLabApiException e) { LOGGER.log(Level.WARNING, "Could not manage project hooks for " + source.getProjectPath() + " on " + server.getServerUrl(), e); } } switch (systemhookMode) { case DISABLE: return; case SYSTEM: if (!server.isManageSystemHooks()) { return; } credentials = server.getCredentials(); if (credentials == null) { LOGGER.log(Level.WARNING, "No System credentials added, cannot create system hook"); } break; case ITEM: credentials = source.credentials(); if (credentials == null) { LOGGER.log(Level.WARNING, "No Item credentials added, cannot create system hook"); } break; default: return; } // add system hooks if (credentials != null) { createSystemHookWhenMissing(server, credentials); } } public static void createSystemHookWhenMissing(GitLabServer server, PersonalAccessToken credentials) { String systemHookUrl = getHookUrl(server, false); try { GitLabApi gitLabApi = new GitLabApi(server.getServerUrl(), credentials.getToken().getPlainText()); SystemHook systemHook = gitLabApi.getSystemHooksApi() .getSystemHookStream() .filter(hook -> systemHookUrl.equals(hook.getUrl())) .findFirst() .orElse(null); if (systemHook == null) { gitLabApi.getSystemHooksApi().addSystemHook(systemHookUrl, server.getSecretToken().getPlainText(), false, false, false); } } catch (GitLabApiException e) { LOGGER.log(Level.INFO, "User is not admin so cannot set system hooks", e); } } /** * @deprecated use {@link #getHookUrl(GitLabServer,boolean)} instead */ @Deprecated public static String getHookUrl(boolean isWebHook) { return getHookUrl(null, isWebHook); } /** * @param server the {@code GitLabServer} for which the hooks URL would be created. If not {@code null} and it * has a {@link GitLabServer#getHooksRootUrl()}, then the hook URL will be based on this root URL. * Otherwise, the hook URL will be based on {@link Jenkins#getRootUrl()}. * @param isWebHook {@code true} to get the webhook URL, {@code false} for the systemhook URL * @return a webhook or systemhook URL */ public static String getHookUrl(GitLabServer server, boolean isWebHook) { String rootUrl = (server == null || server.getHooksRootUrl() == null) ? Jenkins.get().getRootUrl() : server.getHooksRootUrl(); if (StringUtils.isBlank(rootUrl)) { return ""; } checkURL(rootUrl); UriTemplateBuilder templateBuilder = UriTemplate.buildFromTemplate(rootUrl); if (isWebHook) { templateBuilder.literal("gitlab-webhook"); } else { templateBuilder.literal("gitlab-systemhook"); } return templateBuilder.literal("/post").build().expand(); } static void checkURL(String url) { try { URL anURL = new URL(url); if ("localhost".equals(anURL.getHost())) { throw new IllegalStateException( "Jenkins URL cannot start with http://localhost \nURL is: " + url); } if (!anURL.getHost().contains(".")) { throw new IllegalStateException( "You must use a fully qualified domain name for Jenkins URL, this is required by GitLab" + "\nURL is: " + url); } } catch (MalformedURLException e) { throw new IllegalStateException("Bad Jenkins URL\nURL is: " + url); } } public static ProjectHook createWebHook() { ProjectHook enabledHooks = new ProjectHook(); enabledHooks.setPushEvents(true); enabledHooks.setMergeRequestsEvents(true); enabledHooks.setTagPushEvents(true); enabledHooks.setNoteEvents(true); return enabledHooks; } public static String createWebHookWhenMissing(GitLabApi gitLabApi, String project, String hookUrl, String secretToken) throws GitLabApiException { ProjectHook projectHook = gitLabApi.getProjectApi().getHooksStream(project) .filter(hook -> hookUrl.equals(hook.getUrl())) .findFirst() .orElseGet(GitLabHookCreator::createWebHook); if (projectHook.getId() == null) { gitLabApi.getProjectApi().addHook(project, hookUrl, projectHook, false, secretToken); return "created"; } // Primarily done due to legacy reason, secret token might not be configured in previous releases. So setting up hook url with the token. if(!isTokenEqual(projectHook.getToken(), secretToken)) { projectHook.setToken(secretToken); gitLabApi.getProjectApi().modifyHook(projectHook); return "modified"; } return "already created"; } public static boolean isTokenEqual(String str1, String str2) { if(str1 == null && str2.isEmpty()) { return true; } if(str1 == null) { return false; } return str1.equals(str2); } }