<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>jenkins on
A Scripter's Notes</title><link>https://scripter.co/tags/jenkins/</link><description>Recent content in jenkins
on A Scripter's Notes</description><language>en-us</language><managingEditor>kaushal.modi@gmail.com (Kaushal Modi)</managingEditor><webMaster>kaushal.modi@gmail.com (Kaushal Modi)</webMaster><lastBuildDate>Wed, 22 Apr 2026 08:24:58 -0400</lastBuildDate><generator>Hugo -- gohugo.io</generator><docs>https://validator.w3.org/feed/docs/rss2.html</docs><atom:link href="https://scripter.co/tags/jenkins/index.xml" rel="self" type="application/rss+xml"/><item><title>Version controlling Jenkins config</title><link>https://scripter.co/version-controlling-jenkins-config/</link><description>&lt;blockquote>Jenkins is an amazing free and open source continuous integration and
deployment software. But its primary means of configuration is a web
UI, and recently that cost me a lot of debug time. That set me down
the path of figuring out a way to version control the Jenkins config
(the &lt;code>$JENKINS_HOME&lt;/code> directory).&lt;/blockquote>&lt;div class="ox-hugo-toc toc">
&lt;div class="heading">Table of Contents&lt;/div>
&lt;ul>
&lt;li>&lt;a href="#what-bit-me">What bit me&lt;/a>&lt;/li>
&lt;li>&lt;a href="#dot-gitignore-for-jenkins-config">&lt;code>.gitignore&lt;/code> for Jenkins config&lt;/a>&lt;/li>
&lt;li>&lt;a href="#jenkins-plugin-manager">Jenkins Plugin Manager&lt;/a>&lt;/li>
&lt;li>&lt;a href="#full-solution">Full solution&lt;/a>&lt;/li>
&lt;/ul>
&lt;/div>
&lt;!--endtoc-->
&lt;p>&lt;a href="https://www.jenkins.io/">Jenkins&lt;/a> is a wonderful piece of software and I use it with my
Bitbucket git repos for &lt;a href="https://en.wikipedia.org/wiki/CI/CD">CI/CD&lt;/a>.&lt;/p>
&lt;p>Jenkins uses a web UI for its configuration. I dislike that because
it&amp;rsquo;s difficult to document the configuration process without
screenshots, and if I need to create a new server, it&amp;rsquo;s a manual
process of clicking through tabs and filling in the text boxes. I
didn&amp;rsquo;t mind this enough to do anything about it .. that is until I
finally got bit by it.&lt;/p>
&lt;h2 id="what-bit-me">What bit me&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#what-bit-me">#&lt;/a>&lt;/h2>
&lt;p>Without going into too much detail, that issue was multi-fold:&lt;/p>
&lt;ol>
&lt;li>I had unknowingly messed up the &lt;em>Project-based Matrix Authorization
Strategy&lt;/em> such that other users in my team were not able to view
the Jenkins jobs.&lt;/li>
&lt;li>I had also updated the Jenkins server that introduced a bug
(&lt;a href="https://issues.jenkins.io/browse/JENKINS-68748">JENKINS-68748&lt;/a>) where the &lt;em>Test LDAP Settings&lt;/em> failed with an
error, but the LDAP authentication actually worked!&lt;/li>
&lt;li>I had also updated all the plugins after updating Jenkins. So if I
rolled back the Jenkins versions, most of the plugins would fail
because of incompatibility with the older Jenkins version. I had
updated Jenkins after months!&lt;/li>
&lt;/ol>
&lt;p>That&amp;rsquo;s when I wished that my whole Jenkins was
version-controlled. That would have allowed me to roll back to the
last working &amp;ldquo;Jenkins image&amp;rdquo; with the Jenkin version, plugins'
versions and my Jenkins config all in sync.&lt;/p>
&lt;p>I had delayed doing this because my &lt;code>$JENKINS_HOME&lt;/code> was more than 1GB
in size and I didn&amp;rsquo;t have time or motivation to figure out what stuff
I should commit and what I should ignore .. But no more &amp;mdash; The time
had finally come.&lt;/p>
&lt;h2 id="dot-gitignore-for-jenkins-config">&lt;code>.gitignore&lt;/code> for Jenkins config&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#dot-gitignore-for-jenkins-config">#&lt;/a>&lt;/h2>
&lt;p>So I did what any good engineer would do .. start looking for a
solution online. I found &lt;a href="https://stackoverflow.com/a/4695615">this StackOverflow answer&lt;/a> for &lt;em>Is there a way
to keep Hudson / Jenkins configuration files in source control?&lt;/em>.&lt;/p>
&lt;p>That answer shares a &lt;code>.gitignore&lt;/code> that ignores files not necessary for
configuring a Jenkins server &amp;mdash; Example: job builds, workspace, log
files, etc. But it didn&amp;rsquo;t work out of the box because the plugin
version info wasn&amp;rsquo;t getting committed correctly. I had committed
everything to git after using the suggested &lt;code>.gitignore&lt;/code> and pushed to
my git remote. But if I cloned that repo to a different area and
attempted to start the Jenkins server from there, it crashed with this
message:&lt;/p>
&lt;p>&lt;a id="code-snippet--jenkins-crash-log">&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">2022-07-15 13:07:06.082+0000 [id=31] SEVERE jenkins.InitReactorRunner$1#onTaskFailed: Failed Loading global config
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">com.thoughtworks.xstream.mapper.CannotResolveClassException: hudson.security.ProjectMatrixAuthorizationStrategy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:81)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:55)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:79)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:74)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.SecurityMapper.realClass(SecurityMapper.java:71)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at hudson.util.XStream2$CompatibilityMapper.realClass(XStream2.java:411)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at hudson.util.xstream.MapperDelegate.realClass(MapperDelegate.java:46)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:47)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at hudson.util.RobustReflectionConverter.determineType(RobustReflectionConverter.java:521)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> at hudson.util.RobustReflectionConverter.doUnmarshal(RobustReflectionConverter.java:346)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Caused: jenkins.util.xstream.CriticalXStreamException:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">---- Debugging information ----
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cause-message : hudson.security.ProjectMatrixAuthorizationStrategy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">class : hudson.model.Hudson
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">required-type : hudson.model.Hudson
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">converter-type : hudson.util.RobustReflectionConverter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">path : /hudson/authorizationStrategy
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">line number : 12
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">version : not available
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">-------------------------------
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="src-block-caption">
&lt;span class="src-block-number">&lt;a href="#code-snippet--jenkins-crash-log">Code Snippet 1&lt;/a>:&lt;/span>
Snippet of Jenkins crash when attempting to run the server from the freshly cloned git repo
&lt;/div>
&lt;h2 id="jenkins-plugin-manager">Jenkins Plugin Manager&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#jenkins-plugin-manager">#&lt;/a>&lt;/h2>
&lt;p>So I &lt;a href="https://community.jenkins.io/t/version-controlling-jenkins-config-help-defining-a-gitignore-that-minimizes-the-git-repo-size/3036">reached out for help&lt;/a> on the Jenkins Community. One of the key
contributors to Jenkins, &lt;a href="https://community.jenkins.io/u/MarkEWaite">Mark Waite&lt;/a>, was tremendously helpful. He
suggested using his &lt;a href="https://github.com/jenkinsci/plugin-installation-manager-tool">&lt;code>jenkins-plugin-manager&lt;/code>&lt;/a> tool. After trying it out
for a bit, I realized that this tool had everything I needed for
version controlling the plugin versions:&lt;/p>
&lt;ul>
&lt;li>Ability to save a list of installed Jenkins plugins and their
versions to a file.&lt;/li>
&lt;li>Ability to batch install all the plugins of the versions listed in a
file.&lt;/li>
&lt;/ul>
&lt;p>This was like doing Python&amp;rsquo;s &lt;a href="https://scripter.co/saving-python-pip-dependencies/">plugin management using
&lt;code>requirements.txt&lt;/code>&lt;/a>, except that this was for Jenkins.&lt;/p>
&lt;h2 id="full-solution">Full solution&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#full-solution">#&lt;/a>&lt;/h2>
&lt;p>With a combination of the &lt;code>.gitignore&lt;/code> that I started with from that
SO answer, managing plugins using &lt;code>jenkins-plugin-manager&lt;/code>, tweaking
the &lt;code>.gitignore&lt;/code> to my liking, and adding helper Bash scripts for
downloading and running Jenkins server binaries, and doing the plugin
management, I finally got what I needed:&lt;/p>
&lt;div class="org-center">
&lt;p>&lt;a href="https://github.com/kaushalmodi/jenkins-minimal">https://github.com/kaushalmodi/jenkins-minimal&lt;/a>&lt;/p>
&lt;/div>
&lt;p>The README on the repo has all the instructions.&lt;/p></description><author>Kaushal.Modi@fakeEmailToMakeValidatorHappy.com (Kaushal Modi)</author><category domain="https://scripter.co/categories/unix">unix</category><category domain="https://scripter.co/tags/git">git</category><category domain="https://scripter.co/tags/jenkins">jenkins</category><category domain="https://scripter.co/tags/100daystooffload">100DaysToOffload</category><guid>https://scripter.co/version-controlling-jenkins-config/</guid><pubDate>Wed, 20 Jul 2022 00:18:00 -0400</pubDate></item></channel></rss>