/******************************************************************************* * Copyright (c) 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package com.ibm.team.build.internal.hjplugin.util; import hudson.model.AbstractProject; import hudson.scm.SCM; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashSet; import java.util.List; import java.util.Set; import com.ibm.team.build.internal.hjplugin.RTCBuildResultAction; import com.ibm.team.build.internal.hjplugin.RTCScm; public class RTCScmConfigHelper { private static final String MULTI_SCM = "org.jenkinsci.plugins.multiplescms.MultiSCM"; private static final String SLASH = "/"; //$NON-NLS-1$ /** * If the project is using the MultiScm plugin as its configured SCM provider, * find the RTC Scm configuration(s) for the plugin. * @param project The project whose RTCScms are to be located * @param projectScms set of RTC Scms updated with the RTC SCMs found */ private static void resolveMultiScmIfConfigured(AbstractProject<?, ?> project, Set<RTCScm> projectScms) { SCM projectScm = project.getScm(); // Use reflection to determine if this is an instance of // org.jenkinsci.plugins.multiplescms.MultiSCM and see if RTCScm is being used // If this doesn't match because we are dealing with a subclass, then we need to dig // deeper at the classes. Not doing it now because it is not necessary and would add // extra overhead on all deletes of builds/projects when neither RTC nor the Multi SCM // plugin are configured. if (MULTI_SCM.equals(projectScm.getClass().getCanonicalName())) { getRTCScm(projectScm, projectScms); } } /** * Find the RTCScm configuration that best matches the one is appropriate * for the server referenced by the build result action. * * Its possible that the project (job) has more than 1 RTC Scm configured for it. * In that case try to match based on server uri. Otherwise assume that the current * SCM configuration is appropriate for the build result. * * The action does have an SCM associated with it, but it is transient. So it could be * null by now. But even if it isn't null, the credential info could be stale, so * look for the configuration on the project now. It is possible to return null * (using some other multi-scm plugin that we don't know about, changed the configuration * of the project since the build was run). * @param rtcScmConfigs The current RTC SCM configuration(s) for the project/job that was built. * @param buildResultAction Hint from the build created by the project. It hints at * the RTC Scm configuration desired if more there is more than 1. * @return The RTC Scm configuration of the project if found. <code>null</code> otherwise. */ public static RTCScm findRTCScm(Set<RTCScm> rtcScmConfigs, RTCBuildResultAction buildResultAction) { if (rtcScmConfigs.size() == 1) { // simple case - the build result should of been created by this SCM return rtcScmConfigs.iterator().next(); } else if (rtcScmConfigs.size() > 0) { // go through the scm configurations and see which is the best match for the build result // Actions may add a trailing slash so normalize so both sides of the comparison have it. String serverURI = buildResultAction.getServerURI(); if (serverURI != null) { if (!serverURI.endsWith(SLASH)) { serverURI = serverURI + SLASH; } for (RTCScm projectScm : rtcScmConfigs) { String scmServerUri = projectScm.getServerURI(); if (scmServerUri != null && !scmServerUri.endsWith(SLASH)) { scmServerUri = scmServerUri + SLASH; } if (serverURI.equals(scmServerUri)) { return projectScm; } } } } return null; } @SuppressWarnings("unchecked") /** * Get from the Multi-SCM plugin SCM the configured RTCScms if any * @param multiScm The Multi-SCM plugin configured SCM provider * @param projectScms The set of RTCScm(s) found. Updated. */ private static void getRTCScm(SCM multiScm, Set<RTCScm> projectScms) { try { // Yes we are implementation aware. Method m = multiScm.getClass().getMethod("getConfiguredSCMs", (Class[]) null); // $NON-NLS-N$ Object result = m.invoke(multiScm, (Object[]) null); if (result instanceof List) { for (Object configuredScm : (List<Object>) result) { if (configuredScm instanceof RTCScm) { projectScms.add((RTCScm) configuredScm); } } } } catch (NoSuchMethodException e) { // not the plugin we expected } catch (IllegalArgumentException e) { // not the plugin we expected } catch (IllegalAccessException e) { // not the plugin we expected } catch (InvocationTargetException e) { // not the plugin we expected } } /** * Find the RTCScm config instance(s) the project is currently configured with. * If this project is using the multi-scm, then there could be >1 RTCScm configured. * @param project The project to find the RTCScm configs currently in use * @return The RTCScm configs for the project. May be empty, never <code>null</code> */ public static Set<RTCScm> getCurrentConfigs(AbstractProject<?, ?> project) { Set<RTCScm> projectScms = new HashSet<RTCScm>(); if (project != null) { SCM scm = project.getScm(); if (scm instanceof RTCScm) { projectScms.add((RTCScm) scm); } else if (scm != null) { // see if this is a multi-scm project with 1 or more RTC SCMs. resolveMultiScmIfConfigured(project, projectScms); } } return projectScms; } }