/** * Copyright Promptu Systems Corporation 2016. All rights reserved. */ package p4; import java.io.FileReader; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.httpclient.HttpException; import com.perforce.p4java.core.ChangelistStatus; import com.perforce.p4java.core.IChangelistSummary; import com.perforce.p4java.exception.AccessException; import com.perforce.p4java.exception.ConfigException; import com.perforce.p4java.exception.ConnectionException; import com.perforce.p4java.exception.NoSuchObjectException; import com.perforce.p4java.exception.RequestException; import com.perforce.p4java.exception.ResourceException; import com.perforce.p4java.server.IServer; import com.perforce.p4java.server.ServerFactory; import bugzilla.rest.BugzillaListener; /** * Perforce Bugzilla Bridge. * * This utility uses the Perforce Java API to monitor the Perforce server and detect * when a changelist has been submitted that contains words that indicate a bug in * Bugzilla has been named. When it detects a bug being named it copies the contents * of the changelist description into the bug as a comment. If the changelist description * contains the word "bugfix" the bug is also marked RESOLVED/FIXED and the assignee * is set to the QA contact. * * <pre> * java -cp p4bugzilla.jar:<other jars> p4.P4Bugzilla /etc/p4bugzilla.conf & * </pre> * * @see ChangeListener * @author Warwick Hunter * @since 2016-11-25 */ public class P4Bugzilla implements Runnable { /** The counter maintained by the p4 server that holds the highest current change number */ private static final String MAX_CHANGE_COUNTER = "change"; private static final Logger s_logger = Logger.getLogger("p4bugzilla"); private final IServer m_server; private final String m_counter; private final List<ChangeListener> m_listeners = new ArrayList<ChangeListener>(); /** * Constructor. * * @throws URISyntaxException * @throws ResourceException * @throws ConfigException * @throws NoSuchObjectException * @throws ConnectionException * @throws RequestException * @throws AccessException * @throws IOException * @throws XmlRpcException * @throws HttpException */ public P4Bugzilla(Properties props) throws ConnectionException, NoSuchObjectException, ConfigException, ResourceException, URISyntaxException, AccessException, RequestException, HttpException, IOException { m_counter = props.getProperty("p4.counter", "p4bugzilla"); String p4Uri = String.format("p4java://%s", props.getProperty("p4.port")); String bugzillaHost = props.getProperty("bugzilla.host"); String bugzillaUser = props.getProperty("bugzilla.user"); String bugzillaPassword = props.getProperty("bugzilla.password"); String swarmUrl = props.getProperty("swarm.url"); s_logger.info(String.format("Connection to Perforce %s as user %s", p4Uri, props.getProperty("p4.user"))); m_server = ServerFactory.getServer(p4Uri, props); m_server.setUserName(props.getProperty("p4.user")); m_server.connect(); s_logger.info(String.format("Connection to Bugzilla %s as user %s", bugzillaHost, bugzillaUser)); m_listeners.add(new BugzillaListener(bugzillaHost, bugzillaUser, bugzillaPassword, swarmUrl)); } /** * Check the counter every five seconds. */ @Override public void run() { while (true) { checkCounter(); try { Thread.sleep(5000); } catch (InterruptedException e) { s_logger.log(Level.FINE, "Sleep interrupted", e); } } } /** * Notify listeners about the change. */ private void notifyListeners(IChangelistSummary chng) { for (ChangeListener listener : m_listeners) { listener.handleChange(chng); } } /** * Check to see if the counter has changed. */ private void checkCounter() { int lastChangeNumber = 0; try { int maxChangeNumber = Integer.parseInt(m_server.getCounter(MAX_CHANGE_COUNTER)); lastChangeNumber = Integer.parseInt(m_server.getCounter(m_counter)); while (lastChangeNumber < maxChangeNumber) { if (lastChangeNumber > 0 && lastChangeNumber < maxChangeNumber) { try { IChangelistSummary changelist = m_server.getChangelist(++lastChangeNumber); if (changelist != null && changelist.getStatus() != ChangelistStatus.NEW) { notifyListeners(changelist); } } catch (RequestException e) { if (!e.getMessage().startsWith("Change") || !e.getMessage().contains("unknown.")) { e.printStackTrace(); } ++lastChangeNumber; } } } } catch (Exception e) { s_logger.log(Level.WARNING, "Problem interacting with p4 server", e); return; } try { m_server.setCounter(m_counter, Integer.toString(lastChangeNumber), false); } catch (Exception e) { /* If the counter can not be set, die an ugly death. */ /* It's better to die, then to spam users with e-mail. */ s_logger.log(Level.SEVERE, "Unable to set the p4 counter", e); System.exit(-1); } } /** * Command line execution method. The command line takes a single argument, which is the path to the configuration file. */ public static void main(String[] argv) { try { Properties props = new Properties(); props.load(new FileReader(argv[0])); if (props.getProperty("bugzilla.host") == null || props.getProperty("bugzilla.user") == null || props.getProperty("bugzilla.password") == null) { System.out.println("Bugzilla host, user and password must be set"); return; } new P4Bugzilla(props).run(); } catch (Exception e) { s_logger.log(Level.SEVERE, "Unable to communicate with p4", e); } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 21161 | Warwick Hunter |
P4 Bugzilla v2.1 - Use the new Bugzilla REST API instead of the old XMLRPC API. - Use the latest P4 Java API. - Build with gradle and gradlew. - Integrate with the latest systemd Linux daemon startup environment found on Fedora 21+ systems. - Simplified the code to focus on just the job at hand. |