An Improved Jenkins SCM Sync Configuration Plugin

This plugin has been deprecated due to Jenkins API changes. It is no longer functional.

One of my favorite Jenkins plugins is the SCM Sync Configuration plugin. There have been multiple occasions where I have made a change to a project configuration only to break the build. When that happened, there was no way to undo the changes and revert back to the previous configuration.

The SCM Sync Configuration plugin is a godsend, as all of your configuration settings are backed up to an SCM system (git, in my case). If you make a bad change, you can revert to an older commit or simply use the repository as a reference to manually undo your changes.

Unfortunately, if you use the mainline plugin you will find that syncing no longer works once you’ve deleted a job. This can be especially problematic if you are using multi-branch pipeline builds, as jobs are regularly created and deleted to correspond with active branches and pull requests.

Since the plugin seems to be currently unmaintained, I forked the repository and included fixes from elsewhere on the web. Using this new plugin version, I am happy to report that all of my SCM syncing woes have been solved.

Below I’ll describe how to use my version of the SCM Sync Configuration plugin on your own Jenkins instance.

GitHub Repository

The Embedded Artistry SCM Sync Configuration plugin is hosted on GitHub. As a shortcut, here is a handy git clone reference:

git clone git@github.com:embeddedartistry/scm-sync-configuration-plugin.git

Releases

My local Jenkins instance generates plugin images. I have decided to use the GitHub releases feature to distribute binaries. If you would like to use a pre-generated plugin image, simply download the scm-sync-configuration.hpi plugin from GitHub.

Manually Building the Plugin

If you’d prefer to build locally, the process is quite simple.

First, you’ll need to install Maven. Once installed, the plugin can be built by issuing the following command:

mvn install

After the build is complete, the plugin can be found at ./target/scm-sync-configuration.hpi

Installing the Plugin

If you have the existing plugin installed, uninstall it from using the Jenkins plugin manager. Then follow the instructions below to manually install scm-sync-configuration.hpi from the Jenkins web interface.

Assuming a .hpi file has been downloaded, a logged-in Jenkins administrator may upload the file from within the web UI:

  1. Navigate to the Manage Jenkins > Manage Plugins page in the web UI.
  2. Click on the Advanced tab.
  3. Choose the .hpi file under the Upload Plugin section.
  4. Upload the plugin file.

You can review the Managing Plugins documentation for further information and other approaches to installing the plugin.

References

13 Replies to “An Improved Jenkins SCM Sync Configuration Plugin”

  1. Good morning! I am trying to use this plugin, but am receiving a message when I click the "Save" button.

    Any ideas on what I can do to fix it?
    Thanks!

    Stack trace:
    java.lang.NoSuchMethodError: org.apache.http.impl.client.cache.CacheConfig.setNeverCache1_0ResponsesWithQueryString(Z)V
    at com.atlassian.httpclient.apache.httpcomponents.DefaultHttpClient.<init>(DefaultHttpClient.java:155)
    at com.atlassian.jira.rest.client.internal.async.AsynchronousHttpClientFactory.createClient(AsynchronousHttpClientFactory.java:53)
    at com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory.create(AsynchronousJiraRestClientFactory.java:35)
    at com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory.createWithBasicHttpAuthentication(AsynchronousJiraRestClientFactory.java:42)
    at org.jenkinsci.plugins.JiraTestResultReporter.JiraTestDataPublisher$JiraTestDataPublisherDescriptor.configure(JiraTestDataPublisher.java:371)
    at jenkins.model.Jenkins.configureDescriptor(Jenkins.java:3681)
    at jenkins.model.Jenkins.doConfigSubmit(Jenkins.java:3645)
    at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
    at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:343)
    at org.kohsuke.stapler.interceptor.RequirePOST$Processor.invoke(RequirePOST.java:77)
    at org.kohsuke.stapler.PreInvokeInterceptedFunction.invoke(PreInvokeInterceptedFunction.java:26)
    at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:184)
    at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:117)
    at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:129)
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:715)
    Caused: javax.servlet.ServletException
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:765)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:845)
    at org.kohsuke.stapler.Stapler.invoke(Stapler.java:649)
    at org.kohsuke.stapler.Stapler.service(Stapler.java:238)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:841)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
    at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:154)
    at hudson.plugins.scm_sync_configuration.extensions.ScmSyncConfigurationFilter$1.call(ScmSyncConfigurationFilter.java:49)
    at hudson.plugins.scm_sync_configuration.extensions.ScmSyncConfigurationFilter$1.call(ScmSyncConfigurationFilter.java:44)
    at hudson.plugins.scm_sync_configuration.ScmSyncConfigurationDataProvider.provideRequestDuring(ScmSyncConfigurationDataProvider.java:106)
    at hudson.plugins.scm_sync_configuration.extensions.ScmSyncConfigurationFilter.doFilter(ScmSyncConfigurationFilter.java:44)
    at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:151)
    at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:157)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
    at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:99)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84)
    at hudson.security.UnwrapSecurityExceptionFilter.doFilter(UnwrapSecurityExceptionFilter.java:51)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
    at jenkins.security.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:117)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
    at org.acegisecurity.providers.anonymous.AnonymousProcessingFilter.doFilter(AnonymousProcessingFilter.java:125)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
    at org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:142)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
    at org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
    at jenkins.security.BasicHeaderProcessor.doFilter(BasicHeaderProcessor.java:93)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
    at org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
    at hudson.security.HttpSessionContextIntegrationFilter2.doFilter(HttpSessionContextIntegrationFilter2.java:67)
    at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:87)
    at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:90)
    at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:171)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
    at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:49)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
    at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:82)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
    at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
    at org.eclipse.jetty.server.Server.handle(Server.java:564)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110)
    at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
    at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128)
    at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:199)
    at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

  2. This is an amazing piece of work!! I was having exactly the problems described and this worked like a charm!

  3. Hi Phillip! First of all, thanks for your great job on updating this plugin, very helpful!

    I’m having problems to use it with a local git repo (both Ubuntu and Windows), the "Repository <repo_path> is inaccessible. If youre sure it exists, verify that the OS user running Jenkins can actually access it. Check ssh keys, and verify that the OS user has user.name and user.email set" problem.

    I followed all tutorials on Jenkins Wiki page for this plugin, without success. Can you help me with that? Anything will help.

    Thanks.

  4. Hello Guilherme,

    Unfortunately I have never encountered that issue. However, one thing to note is that Jenkins often runs with a different user account than the one that you normally work in.

    It could be that this user (e.g. jenkins) does not have SSH keys configured or does not have a git user.name or user.email set.

    Hope that helps!

  5. Thanks a lot for your efforts! Exactly what I need.

    I would like to suggest that you create a release which does not contain a SNAPSHOT version in its POM. Your current release is 0.0.11-SNAPSHOT, but should better be 0.0.11.

    Thanks!
    Bernd

  6. Hi Phil,

    this is a great effort (I haven’t tried it yet but I will). I am just wondering why didn’t you create a PR into the main project instead of forking it?

    Thanks for the work

  7. If you’re having trouble with repo access, try sshing to it. e.g. try “ssh git@github.com” or whatever repo you’re using, to see if it recognises you. If that works, try doing it inside a Jenkins build task, to see how it reacts. You’ll probably get an error message that tells you what’s wrong.

  8. After installing the plugin, and configuring a repository, I was expecting that it would check something into my gitlab repository. But alas, it remains empty. The sync status at the bottom is saying everything is ok and synced. Is that what I should expect to happen, something getting pushed to my repository?

  9. Unfortunately the plugin stopped working in November/December timeframe – I”m guessing there was a Jenkins API change, and now it no longer functions. I am not a Java/Groovy developer, so no chance I can get it working again. I will add a note to the top of this article.

Share Your Thoughts

This site uses Akismet to reduce spam. Learn how your comment data is processed.