Files
JIMRI/help/en/html/doc/Technical/ContinuousIntegration.shtml
T
2026-06-17 14:00:51 +02:00

300 lines
13 KiB
Plaintext

<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content="HTML Tidy for HTML5 for Apple macOS version 5.8.0">
<title>JMRI: Continuous Integration</title>
<meta name="author" content="Bob Jacobsen">
<meta name="keywords" content="JMRI technical code Continuous Integration jenkins test testing ci workflow">
<!--#include virtual="/help/en/parts/Style.shtml" -->
</head>
<body>
<!--#include virtual="/help/en/parts/Header.shtml" -->
<div id="mBody">
<!--#include virtual="Sidebar.shtml" -->
<div id="mainContent">
<h1>JMRI Code: Continuous Integration</h1>
<p>"Continuous Integration" is the process of rebuilding a system every time it changes, so
that you rapidly learn of new problems and are motivated to remove existing ones.</p>
<p>The core of our system is a series of
<a href="#mandatory">GitHub Actions</a> and
<a href="#jenkins">Jenkins</a> jobs that routinely
build the code, run checks, and creates downloadable installers. That means that we can and
do put changes into our users hands very quickly. There's a <a href="CI-status.shtml">CI
status page</a> that shows the combined status of that.</p>
<p>We divide these into three groups:</p>
<ul>
<li>
<a href="#mandatory">Mandatory checks</a> that must be OK before the change will be
merged.
</li>
<li>
<a href="#optional">Optional checks</a> that provide additional information on the code.
These don't have to be completely cleared before a change is merged, but their
observations should be considered and their metrics should be improving.
</li>
<li>
<a href="#independent">Independent checks</a> that are run by our <a href=
"#jenkins">Jenkins instance</a> on a periodic basis to look for deeper problems.
</li>
</ul>
<p>These checks can be run locally by developers before uploading changes to Github,
see <a href="JUnit.shtml#run">Running JUnit Tests</a>.</p>
<h2 id="mandatory">Mandatory Checks</h2>
<p>We use multiple
<a href="https://docs.github.com/en/actions">GitHub actions</a>
to test every proposed change entered into our GitHub code repository
before it gets merged.</p>
<ul>
<li>
<a href="#winCI">Windows CI tests</a>
</li>
<li>
<a href="#headless">Headless Tests</a>
</li>
<li>
<a href="#separate">Separate Tests</a>
</li>
<li>
<a href="#static">Static Analysis</a>
</li>
<li>
<a href="#process">Process steps</a>
</li>
</ul>
<p>These checks are defined by files in the <code>.github/</code> directory.</p>
<p>They normally run both on PRs to the main <code>JMRI/JMRI</code> repository,
but also on pushes and PRs to your own repository.</p>
<p>If you want to turn that off,</p>
<a href="images/ActionSettings.png"><img src="images/ActionSettings.png"
class="floatRight" alt="github actions"></a>
<ol>
<li>On the page for your own repository, select "Settings"</li>
<li>From the left sidebar, select "Actions"</li>
<li>Pick on option for what can run. The bottom option turns everything off for you
locally.</li>
</ol>
<p>Note that if you turn this off, the "Actions" tab won't show in the GitHub web interface
until you turn it back on.</p>
<h3 id="winCI">Windows CI tests</h3>
<p>This runs "AllTest", our test suite of over 30,000
<a href="JUnit.shtml">JUnit tests</a> on a Windows server. A screen buffer (not a real
screen) is used for all the GUI tests. All tests must pass.</p>
<h3 id="headless">Headless tests</h3>
<p>Reruns the JUnit test suite in "java.awt.Headless=true" mode to ensure that
the parts of JMRI that are meant to run without a GUI really can. This is about 80%
of the test suite. These are run on Linux. All tests must pass.</p>
<h3 id="separate">Separate tests</h3>
<p>About a hundred JUnit graphical tests are run separately from AllTest
to ensure they have a clean environment. These are run on Linux. All tests must pass.</p>
<h3 id="static">Static analysis</h3>
<p>This runs a series of static analysis checks:</p>
<ul>
<li>A pass of the ECJ compiler with warnings on
<li><a href="SpotBugs.shtml">Spotbugs</a>
<li>CheckStyle
<li>A Javadoc generation and check
<li>A scan of the help files with htmllint
<li>And a set of architecture checks of interpackage references, etc.
</ul>
<p>Any errors or warnings fail this step.</p>
<h3 id="process">Process steps</h3>
<p>There are a few additional actions that are used as process controls:</p>
<ul>
<li>Checks consistency of TypeScript and Javascript files.
<li>Set flags that represent whether a PR might need localization,
and whether it contains updated help files.
<li>If needed, reminds the author to add to the release note
<li>Prevent PRs marked "WIP" (Work In Progress) from <a href="https://github.com/apps/wip">being merged</a>
<li>Require that PRs be approved by a 2nd party before being merged
<li>And enforce a 24-hour waiting period so that the world-wide team
can get a look at the PR.
</ul>
<h2 id="optional">Optional Checks</h2>
<p>We also run advisory checks on every pull request (PR). Although we don't require that they
have zero warnings, we strongly
recommend that people look at them and try to improve their metrics of test coverage,
simplicity and understandability, etc.</p>
<ul>
<li>
<a href="#CodeClimate">CodeClimate</a>
</li>
</ul>
<h3 id="CodeClimate">Code Climate</h3>
<p>The <a href="https://codeclimate.com/github/JMRI/JMRI/">Code Climate</a> points out places
where the code appears to be complex in various ways. (It also provides coverage information,
though <a href="#jacoco">JaCoCo</a> seems to do a better job of that.) We recommend you
look at those results and make updates where they make sense, so that things are continuously
improving, but not every suggestion it makes is worth it, or even appropriate. We don't
require this to be clean before merging.</p>
<p>Code Climate is controlled by the .codeclimate.yml file.</p>
<h2 id="independent">Independent Checks with Jenkins</h2>
<p>JMRI uses the <a href="https://www.jenkins.io/">Jenkins</a> continuous integration engine for
integration and test builds. This includes keeping our <a href="WebSite.shtml">website</a>
up to date as changes are committed, building installer packages from development builds, and
building final releases.</p>
<p>Our primary Jenkins engine is at <a href=
"https://builds.jmri.org/jenkins/">https://builds.jmri.org/jenkins/</a>. Because it's hosted
outside the US, we force its Java locale to US English by setting the <code>LC_ALL</code>
environment variable to <code>en_US</code> in the master Jenkins configuration settings.</p>
<p id="jenkins">Specific Jenkins results of interest:</p>
<ul>
<li>
<a href="https://builds.jmri.org/jenkins/job/development/job/builds/">Builds</a> page,
showing status of the builds done after every series of commits. Successful builds are
followed by building installers via the <a href=
"https://builds.jmri.org/jenkins/job/development/job/packages">Packages</a> job.
These are sometimes referred to as "development builds".
</li>
<li id="jacoco">
<a href="https://builds.jmri.org/jenkins/job/development/job/jacoco/">JaCoCo</a> page,
showing test coverage from our JUnit tests. There's both a summary of overall
coverage, and detailed information on each
<a href="https://builds.jmri.org/jenkins/job/development/job/jacoco/lastBuild/jacoco/jmri.implementation/">class</a> and
<a href="https://builds.jmri.org/jenkins/job/development/job/jacoco/lastBuild/jacoco/jmri.implementation/AbstractAudio/">method</a>.
</li>
<li>
<a href="https://builds.jmri.org/jenkins/job/development/job/spotbugs/">SpotBugs</a>
page, showing status of the more-extensive <a href="SpotBugs.shtml">SpotBugs</a> tests
done periodically. There are also pages of the <a href=
"https://builds.jmri.org/jenkins/job/development/job/spotbugs/changes">most recent
changes</a> and the <a href=
"https://builds.jmri.org/jenkins/job/development/job/spotbugs/lastBuild/">most recent
results</a>.
<p>For more information on JMRI's use of SpotBugs, see the <a href=
"SpotBugs.shtml">separate SpotBugs page</a>.</p>
</li>
</ul>
<h3>Jenkins Integration with NetBeans</h3>
<p>If you are developing in the <a href="NetBeans.shtml">NetBeans 7.0</a> environment, it is
possible to integrate feedback from the Jenkins Continuous Integration (CI) engine.</p>
<p>Within the NetBeans environment, reference is made to the Hudson CI engine - Jenkins is a
<a href="https://en.wikipedia.org/wiki/Fork_(software_development)">"fork"</a> of the Hudson
code and supports the same <a href="https://en.wikipedia.org/wiki/API">API</a>.</p>
<p>Integration into NetBeans is achieved by executing the following steps:</p>
<ol>
<li>Open NetBeans</li>
<li>Switch to the 'Services' window (shortcut key 'Ctrl+5')</li>
<li>Right-click (Ctrl-click on Mac) the entry 'Hudson Builders' and choose 'Add Hudson
Instance...'
<p><img src="images/NetBeansJenkinsAdd.png" alt="Add Hudson Instance...">
</p>
</li>
<li>In the resulting pop-up, complete the following:
<dl>
<dt>Name</dt>
<dd>JMRI</dd>
<dt>URL</dt>
<dd>https://builds.jmri.org/jenkins/</dd>
<dt>Auto refresh every X minutes</dt>
<dd>60 (change from the default of 5 to avoid overloading the CI server)</dd>
</dl>
<img src="images/NetBeansJenkinsAddDialog.png" alt="Add Hudson Instance dialog">
</li>
</ol>
<p>From now on, the current status of the Jenkins builds can be reviewed in the 'Services'
window by expanding the 'JMRI' entry under 'Hudson Builders'.</p>
<p><img src="images/NetBeansJenkinsOverview.png" alt="Jenkins Overview">
</p>
<h3 id="architectureTests">Architecture Tests</h3>
<p><a href="https://github.com/JMRI/JMRI/blob/master/java/test/jmri/ArchitectureTest.java">ArchitectureTest</a>
contains rules which seek to maintain and improve the overall system architecture of JMRI.
<br/>For example, the server classes should not depend on code within the system connection hardware types.</p>
<pre style="font-family: monospace;"> noClasses()
.that().resideInAPackage("jmri.jmris")
.should().dependOnClassesThat().resideInAPackage("jmri.jmrix..");</pre>
<p><a href="https://github.com/JMRI/JMRI/blob/master/java/test/jmri/ArchitectureCheck.java"
>ArchitectureCheck</a> uses FreezingArchRule to collect issues in the archunit_store directory.
<br/>Should new issues be encountered, they'll be reported as errors.
<br/>Please fix them rather than committing a larger store.
</p>
<p>The Test classes also undergo an Architecture Test,
<a href="https://github.com/JMRI/JMRI/blob/master/java/test/jmri/TestArchitectureTest.java"
>TestArchitectureTest</a>.</p>
<p>Running <pre style="font-family: monospace;"> ant test-single -Dtest.includes=jmri.ArchitectureTest</pre>
will fail as no tests are executed.
The build file specifies which JUnit Runners are Launched, i.e.
<pre style="font-family: monospace;"> --include-engine=junit-jupiter --include-engine=junit-vintage</pre>
<br/>Within maven no launchers are specified ( hence all launchers are included ),
though the Architecture tests are excluded from standard CI test executions.</p>
<p>These tests can be run with
<pre style="font-family: monospace;"> mvn -Dtest=jmri.ArchitectureTest,jmri.TestArchitectureTest,jmri.util.FileLineEndingsCheck test</pre>
<h3 id="cucumberTests">Cucumber Tests</h3>
<p><a href="https://en.wikipedia.org/wiki/Cucumber_(software)">Cucumber Tests</a> allow
expected software behaviours to be specified in a logical language.
<br/>These are used to test the Web Server output ( in Firefox and Google Chrome ),
along with Application launches using simulation profiles for various hardware systems.
<br/>The Features and Step Definitions files are in the <a href="https://github.com/JMRI/JMRI/tree/master/java/acceptancetest"
>/java/acceptancetest</a> folder.
<br/>The ant command runs all tests with the class name RunCucumberIT.class ,
so both the apps and jmri tests are performed.</p>
<pre style="font-family: monospace;"> ant cucumber</pre>
<!--#include virtual="/help/en/parts/Footer.shtml" -->
</div>
<!-- closes #mainContent-->
</div>
<!-- closes #mBody-->
<script src="/js/help.js"></script>
</body>
</html>