
An elementary example of a development cycle of a primitive ASP.NET (Mono) application using Jenkins CI, based on the
construction of a “correct” development process on the .NET platform .
The presented example may be of interest to a wide audience, since can easily be adapted for development for any other platform.
Introduction
This article would never have been written if it were not for the original article, which at one time played a key role in shaping my understanding of the development process. And, as the saying goes, "taking the opportunity I want." I want to thank Eugene for his wonderful article, which is just a great start for novice developers! Thank you very much!
')
This article, by and large, is not something fundamentally new. The same C # project, the same tests on NUnit and the same automation on NAnt. But there are nuances. First: Jenkins CI is used as a CI server, and secondly: considerable attention is paid to the analysis and presentation of various project metrics during its assembly.
The article will consistently describe the process of setting up the working environment and creating an assembly project that will automatically track changes in the source code, compile the project, run units and function tests, and also collect metrics such as the number of lines of code, the presence of its duplicates, the presence of in the source code of technical debts (TODO, FIXME, etc.) The core of the project will be the NAnt script, which will be expanded as the material is reviewed. At any stage, the project is working and can be completed, which can be very convenient for those who fail to create the entire project at once or do not need all the functionality presented (and, frankly speaking, it is redundant in some issues).
Workspace
To set up your workspace, you will need:
OS | GNU / Linux ( openSUSE 12.1, LXDE ) | The operating system on the basis of which the continuous integration server will be deployed. |
CIS | Jenkins CI 1.450 | Continuous integration server. |
VCS | Subversion 1.6.17 | Centralized version control system (any other VCS can be used instead of Subversion) |
CLR | Mono 2.6.10 | Platform under which the development is made. |
Testing | NUnit 2.4.8 | A tool for creating and executing tests (unit, non-unit - this already depends on who will create the tests). |
Selenium RC 2.18.0 | A tool for performing functional tests. |
Static code analyze | Gendarme 2.10.0.0 | Static code analyzer. |
Cloneanalyzer 2005-05-30 | A utility for finding duplicate code. |
StyleCopCmd 0.2.1 | Static code analyzer. |
Other tools | NAnt 0.90 | Utility for automatic assembly of the project. |
Firefox 7.0.1 | Web browser with the help of which functional tests will be created and executed (tests can be performed with the help of other browsers) |
Selenium IDE 1.6.0 | IDE to create functional tests. |
To set up the working environment, you must perform the following steps:
1.
Download the DVD image and install the OS (specify LXDE when selecting the desktop environment). Strictly speaking, another Desktop Environment can be used, or not used at all. The example uses LXDE to make the configuration process easier and no more.
2. Configure Repositories:
sudo zypper ar http://download.opensuse.org/repositories/Mono/openSUSE_11.4/ Mono sudo zypper ar http://pkg.jenkins-ci.org/opensuse/ Jenkins
3. Install the necessary packages:
sudo zypper in jenkins mono-complete mono-nunit mono-tools nant subversion-server apache2 http://www.dwheeler.com/sloccount/sloccount-2.26-1.i386.rpm
4. Download and install the necessary utilities that are not supplied as rpm packages (StyleCopCmd and CloneAnalyzer). There are several nuances.
Firstly: there is no possibility to use
binary files under Linux out of the box. The application as a whole works, but due to the rigidly installed path delimiter in line 460 of the ReportBuilder.cs file, the report file is not exactly where it is expected:
private static string GetViolationsFile(string outputXmlFile) { var offp = Path.GetFullPath(outputXmlFile); var f = string.Format( CultureInfo.CurrentCulture, "{0}\\{1}.violations.xml",
The corrected version, as well as the configuration file, can be downloaded
here .
Secondly: DRY plug-in does not recognize CloneAnalyze utility reports and therefore you need to independently convert CloneAnalyze report to one of the clear Jenkins'y (I chose
CPD ). Examples of reports, as well as a quick-written source code converter can be found
here .
Create a directory for additional utilities:
sudo mkdir -p /var/lib/jenkins/tools/{StyleCop,CloneAnalyzer,SeleniumRC}
5. Install plug-ins for Jenkins (Jenkins -> Manage Jenkins -> Manage Plugins -> Available):
Sure to |
Subversion | Allows you to automate the operation of obtaining source code from the svn repository (installed by default) |
Nunit | Allows you to build reports on the results of NUnit. |
NAnt | Allows you to set NAnt scripts as assembly targets for a Jenkins project. |
Static Code Analysis | Required for DRY plugin. |
Task scanner | Allows you to build reports on tags found in the code (TODO and others). |
Slocount | Allows you to build reports on the results of the SLOCCount utility (displays modest code metrics). |
DocLinks | Allows you to place on the main page of the project a link to the project documentation. |
Violations | Allows you to build reports on the results of various utilities. This example is used to display the results of Gendarme and StyleCopCmd. |
DRY | Allows you to build reports on duplicate code found. |
Seleniumhq | Provides links to the Selenium report. |
Warnings | Allows you to build reports, displaying compiler warnings. |
Recommended: |
JobConfigHistory | Stores the history of changes to the project settings. |
Backup | Allows you to simplify the process of creating a backup copy of the server. |
Optional: |
Green balls | Replaces the blue ball on the green. |
Next Build Number | Allows you to set an arbitrary assembly number. |
Sidebar-link | Allows you to create links on the main page of the server and on the pages of projects. |
Description of the demonstration project

Unfortunately, I was unable to come up with a simple, but at the same time not overloaded with the domain logic and convenient for testing project.
The presented project is simple to the obscene - two input fields, two buttons ("Sum" and "Concatenation") and the result.

To create an application, a solution was created, which includes three projects:
- ExampleCore - which focuses all the application logic (for a moment, as many as two methods)!
- ExampleGUI is an application interface (the only one, but this makes the aspx page even more important).
- ExampleUTest - a project with tests (NUnit).
- ExampleFTest - the ExampleFTest folder with functional tests (Selenium), which is not included in the solution, is also located in the root directory.
Creating an assembly script and setting tools
First of all, you need to create a Jenkins project, which is necessary through the web interface available at: http: // localhost: 8080 (if Jenkins is installed on the local computer), click the New Job link, select the project type Build a free- style software project, enter the project name and create it. Project created.
As mentioned earlier, the NAnt script will be the core of the build project; to do this, you need to create in the Build section, the goal that will trigger the script:

In general, there may be several approaches to the organization of the project, which have their own advantages and disadvantages. In the example, all actions are placed in one NAnt script, which is invoked by one command in a Jenkins project. This is convenient in that it is very easy to make an assembly bypassing Jenkins; it is enough just to run the NAnt script. But it is not always convenient to change the build process (you first need to make a change in the NAnt script, then commit, and only then the build process is updated). In contrast to this approach, you can create many goals in the Jenkins project for executing bash scripts and place all the build logic in them. In this case, it is convenient to edit the build process, but you will not be able to build outside Jenkins.
Let's start creating a Nant script that looks like this:
<?xml version="1.0"?> <project name="Example" default="cis" basedir="."> <target name="cis" description="Execute all targets in CIS."> <call target="clean" /> <call target="build" /> <call target="documentation" /> <call target="utest" /> <call target="gendarme" /> <call target="stylecop" /> <call target="sloccount" /> <call target="cloneanalyze" /> <call target="ftest" /> </target> </project>
Those. first, properties (Property) are declared, then targets (Target) are declared, and in conclusion, the main goal is declared (its name is specified in the default property of the script), which in turn calls previously announced ones. The described method is not the only one; instead of creating a target that calls others, you can simply prescribe the dependence of some targets on others, and then the targets will be called automatically.
Further, all the goals that the cis target causes will be implemented. At any stage, the script can be executed, for which purpose it is necessary to comment out unrealized goals and unused properties for the main purpose (cis).
For simplicity, we will declare properties that further reduce the code to us.
The environment variable set by Jenkins:
<property name="work.d" value="${environment::get-variable('WORKSPACE')}" />
Directory in which the tools are collected:
<property name="tools.d" value="/var/lib/jenkins/tools" />
Aliases of various directories, the purpose of which is obvious from the name:
<property name="bin.d" value="${build.conf}/bin"/> <property name="deploy.d" value="/home/vm/public_html" /> <property name="test.res.d" value="test-results" /> <property name="report.d" value="${work.d}/reports" /> <property name="doc.d" value="${work.d}/doc" /> <property name="core.d" value="${work.d}/ExampleCore" /> <property name="gui.d" value="${work.d}/ExampleGUI" /> <property name="utest.d" value="${work.d}/ExampleUTest" /> <property name="ftest.d" value="${work.d}/ExampleFTest" />
Aliases of a binary file and the StyleCopCmd settings file:
<property name="style.exe" value="${tools.d}/StyleCop/Net.SF.StyleCopCmd.Console.exe" /> <property name="style.conf" value="${tools.d}/StyleCop/Settings.StyleCop" />
Aliases of the executable file, the converter and the CloneAnalyzer configuration file:
<property name="clone.jar" value="${tools.d}/CloneAnalyzer/CloneAnalyzer.jar" /> <property name="clone.conf" value="${tools.d}/CloneAnalyzer/comments.conf" /> <property name="clone.conv" value="${tools.d}/CloneAnalyzer/ca2cpd.exe" />
Aliases of the executable file, the wrapping script, as well as the file with the test suite and the name of the host on which the application for SeleniumRC is deployed:
<property name="selen.jar" value="${tools.d}/SeleniumRC/selenium-server-standalone-2.18.0.jar" /> <property name="selen.sh" value="${tools.d}/SeleniumRC/selenium.sh" /> <property name="selen.host" value="http://192.168.56.210" /> <property name="selen.suite" value="${ftest.d}/Main.html" />
Let's start creating goals.
1. First, create a goal to clean up the assembly directory of old artifacts and create the necessary directories:
<target name="clean" description="Remove binary files, recreate report directory."> <echo message="Target starded at: ${datetime::now()}."/> <delete failonerror="false" dir= "${core.d}/${bin.d}"/> <delete failonerror="false" file="${core.d}/ExampleCore.pidb"/> <delete failonerror="false" dir= "${utest.d}/${bin.d}"/> <delete failonerror="false" dir= "${utest.d}/${test.res.d}"/> <delete failonerror="false" file="${utest.d}/ExampleUTest.pidb"/> <delete failonerror="false" dir= "${gui.d}/${bin.d}"/> <delete failonerror="false" dir= "${gui.d}/${test.res.d}"/> <delete failonerror="false" file="${gui.d}/ExampleGUI.pidb"/> <delete failonerror="false" dir= "${report.d}"/> <delete failonerror="false" dir= "${doc.d}"/> <delete failonerror="false" file="${work.d}/stylecop.report"/> <delete failonerror="false" file="${work.d}/stylecop.violations.xml"/> <mkdir dir="${report.d}"/> <mkdir dir="${report.d}/gendarme"/> <mkdir dir="${report.d}/sloccount"/> <mkdir dir="${report.d}/cloneanalyzer"/> <mkdir dir="${report.d}/selenium"/> <mkdir dir="${doc.d}/xml"/> <mkdir dir="${doc.d}/html"/> <echo message="Target completed at: ${datetime::now()}."/> </target>
2. The second step would be to get updates from the repository. Since this operation is performed by Jenkins, in this example, the NAnt script does not contain it, but if there was a need for it, then its place is here.
Create and configure a Subversion repository:
su a2enmod dav a2enmod dav_svn a2enmod mod_authz_svn cd /srv/www/htdocs wget http://tortoisesvn.googlecode.com/svn/trunk/contrib/svnindex/menucheckout.ico wget http://tortoisesvn.googlecode.com/svn/trunk/contrib/svnindex/svnindex.css wget http://tortoisesvn.googlecode.com/svn/trunk/contrib/svnindex/svnindex.xsl mkdir -p /srv/svn/{repos,user_access,html} cat > /etc/apache2/conf.d/subversion.conf << EOF <IfModule mod_alias.c> Alias /repos "/srv/svn/html" </IfModule> <Directory /srv/svn/html> Options +Indexes +Multiviews -FollowSymLinks IndexOptions FancyIndexing \ ScanHTMLTitles \ NameWidth=* \ DescriptionWidth=* \ SuppressLastModified \ SuppressSize order allow,deny allow from all </Directory> <Location /repos/Example> DAV svn SVNListParentPath on SVNPath /srv/svn/repos/Example SVNIndexXSLT "/svnindex.xsl" AuthType Basic AuthName "Subversion" AuthUserFile /srv/svn/user_access/passwdfile AuthGroupFile /srv/svn/user_access/groupfile AuthzSVNAccessFile /srv/svn/user_access/accessfile Require valid-user </Location> EOF cd /srv/svn/repos svnadmin create --fs-type fsfs Example mkdir -p /srv/svn/repos/Example/dav chown -R wwwrun:www Example/{dav,db,locks} touch /srv/svn/user_access/passwdfile chown root:www /srv/svn/user_access/passwdfile chmod 640 /srv/svn/user_access/passwdfile touch /srv/svn/user_access/groupfile cat > /srv/svn/user_access/groupfile << EOF Example_commiters: Admin User Example_readers: Admin User CIS touch /srv/svn/user_access/accessfile cat > /srv/svn/user_access/accessfile << EOF [groups] admin = Admin user = User cis = CIS [/] * = @admin = rw [Example:/] @user = rw @cis = r /sbin/service apache2 restart exit
After that, configure the Subversion plugin:

And also we will set the periodicity of the assembly (to assemble if there are updates, the presence of which should be checked every hour on weekdays):

3. Create a goal that will compile the generation of documentation in the xml format of the ExampleCore and ExampleGUI subprojects:
<target name="build" description="Compiles the source code."> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Building ExampleCore."/> <csc codepage="utf8" target="library" output="${core.d}/${bin.d}/${build.conf}/ExampleCore.dll" doc="${doc.d}/xml/ExampleCore.xml"> <sources> <include name="${core.d}/**.cs"/> </sources> </csc> <copy file="${core.d}/${bin.d}/${build.conf}/ExampleCore.dll" tofile="${gui.d}/${bin.d}/${build.conf}/ExampleCore.dll" /> <copy file="${core.d}/${bin.d}/${build.conf}/ExampleCore.dll" tofile="${utest.d}/${bin.d}/${build.conf}/ExampleCore.dll" /> <echo message="Building ExampleGUI."/> <csc codepage="utf8" target="library" output="${gui.d}/${bin.d}/${build.conf}/ExampleGUI.dll" doc="${doc.d}/xml/ExampleGUI.xml"> <sources> <include name="${gui.d}/**.cs" /> </sources> <references> <include name="System.Web.dll" /> <include name="${gui.d}/${bin.d}/${build.conf}/ExampleCore.dll" /> </references> </csc> <echo message="Target completed at: ${datetime::now()}." /> </target>
Configure the Warnings plugin so that the compiler messages are processed by Jenkins:

In the future, this will allow to receive such reports on the Warning compiler:

4. Generate documentation in html format:
<target name="documentation" description="Generation documentation."> <echo message="Target starded at: ${datetime::now()}."/> <exec program="monodocer" commandline=" -pretty -i:${doc.d}/xml/ExampleCore.xml -assembly:${core.d}/${bin.d}/${build.conf}/ExampleCore.dll -path:${doc.d}/xml"/> <exec program="monodocer" commandline=" -pretty -i:${doc.d}/xml/ExampleGUI.xml -assembly:${gui.d}/${bin.d}/${build.conf}/ExampleGUI.dll -path:${doc.d}/xml"/> <exec program="mdoc" commandline="export-html ${doc.d}/xml -o=${doc.d}/html"/> <echo message="Target completed at: ${datetime::now()}." /> </target>
Configure the DocLinks plugin:

As a result, a link to the documentation will be created on the main page of the project.
5. Build and run unit tests:
<target name="utest" description="Test the source code."> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Building ExampleUTest."/> <csc codepage="utf8" target="library" output="${utest.d}/${bin.d}/${build.conf}/ExampleUTest.dll"> <sources> <include name="${utest.d}/**.cs" /> </sources> <references> <include name="System.Web.dll" /> <include name="${gui.d}/${bin.d}/${build.conf}/ExampleCore.dll" /> <include name="nunit.core.dll" /> <include name="nunit.framework.dll" /> </references> </csc> <echo message="Launch NUnit." /> <nunit2 haltonfailure="false"> <formatter type="Xml" usefile="true" extension=".xml" outputdir="${utest.d}/${test.res.d}" /> <formatter type="Plain" usefile="false" /> <test assemblyname="${utest.d}/${bin.d}/${build.conf}/ExampleUTest.dll" /> </nunit2> <echo message="Target completed at: ${datetime::now()}." /> </target>
Configure the NUnit plugin:

NUnit plugin reports are as follows:

6. Perform static code analysis with Gendarme:
<target name="gendarme"> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Check code by Gendarme."/> <exec program="gendarme" failonerror="false" commandline=" --config GendarmeRules.xml ${core.d}/${bin.d}/${build.conf}/ExampleCore.dll --xml ${report.d}/gendarme/ExampleCore.gendarme.xml --severity medium+ --confidence total"/> <exec program="gendarme" failonerror="false" commandline=" --config GendarmeRules.xml ${gui.d}/${bin.d}/${build.conf}/ExampleGUI.dll --xml ${report.d}/gendarme/ExampleGUI.gendarme.xml --severity medium+ --confidence total"/> <echo message="Target completed at: ${datetime::now()}." /> </target>
... and StyleCopCmd:
<target name="stylecop"> <echo message="Target starded at: ${datetime::now()}."/> <exec program="mono" commandline=" ${style.exe} -r -sc ${style.conf} -d ${work.d} -of ${work.d}/stylecop/stylecop.report"/> <echo message="Target completed at: ${datetime::now()}." /> </target>
To get rid of the error caused by StyleCopCmd:
While saving registry data at /etc/mono/2.0/../registry/last-btime: System.UnauthorizedAccessException: Access to the path "/etc/mono/registry/last-btime" is denied. at System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean anonymous, FileOptions options) [0x00000] in <filename unknown>:0 at System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share) [0x00000] in <filename unknown>:0 at (wrapper remoting-invoke-with-check) System.IO.FileStream:.ctor (string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare) at System.IO.StreamWriter..ctor (System.String path, Boolean append, System.Text.Encoding encoding, Int32 bufferSize) [0x00000] in <filename unknown>:0 at System.IO.StreamWriter..ctor (System.String path, Boolean append, System.Text.Encoding encoding) [0x00000] in <filename unknown>:0 at (wrapper remoting-invoke-with-check) System.IO.StreamWriter:.ctor (string,bool,System.Text.Encoding) at Microsoft.Win32.KeyHandler.SaveRegisteredBootTime (System.String path, Int64 btime) [0x00000] in <filename unknown>:0
Let's create the desired file with write access for everyone:
sudo touch /etc/mono/registry/last-btime sudo chmod 666 /etc/mono/registry/last-btime
Configure the Violations plugin:

So the reports will look like:


There are a few unpleasant moments: firstly: in order for a detailed report on StyleCop to be successfully displayed, the report should be at the root of the project (which breaks the general trend), and secondly: I did not manage to adjust the detailed report on Gendarme ( who faced - I ask for help).
7. Collect metrics:
<target name="sloccount"> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Analyze code by SLOCCount."/> <exec program="sloccount" output="${report.d}/sloccount/sloccount.report" commandline=" --duplicates --wide --details ${work.d}"/> <echo message="Target completed at: ${datetime::now()}." /> </target>
Configure the SLOCCount plugin:

Report example:

8. We search for duplicates in two stages: first, we launch the CloneAnalyzer application, and then we will convert the received report:
<target name="cloneanalyze"> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Find code duplicates by CloneAnalyze."/> <exec program="java" failonerror="false" output="${report.d}/cloneanalyzer/cloneanalyzer.report.txt" commandline=" -jar ${clone.jar} -c ${clone.conf} -f .*\.\(cs\|aspx\) -d ${work.d}"/> <echo message="Convert CloneAnalyze report in CPD report."/> <exec program="mono" failonerror="false" commandline=" ${clone.conv} ${report.d}/cloneanalyzer/cloneanalyzer.report.txt ${report.d}/cloneanalyzer/cloneanalyzer.report.xml"/> <echo message="Target completed at: ${datetime::now()}." /> </target>
Configure the DRY plugin:

Report example:

9. We will perform functional tests, for which we first deploy the application, restart the web server and run the tests themselves:
<target name="ftest"> <echo message="Target starded at: ${datetime::now()}."/> <echo message="Prepare to launch tests."/> <copy todir="${deploy.d}/${bin.d}/"> <fileset basedir="${gui.d}/${bin.d}/${build.conf}"> <include name="*.dll"/> </fileset> </copy> <copy todir="${deploy.d}/"> <fileset basedir="${gui.d}/"> <include name="*.aspx"/> <include name="*.asax"/> <include name="*.config"/> </fileset> </copy> <echo message="Restart apache2 server."/> <exec program="/bin/bash" commandline="-c 'sudo /etc/init.d/apache2 restart'"/> <echo message="Testing project by Selenium."/> <exec program="${selen.sh}" failonerror="false" commandline=" -htmlSuite *firefox ${selen.host} ${selen.suite} ${report.d}/selenium/selenium.html"/> <echo message="Target completed at: ${datetime::now()}." /> </target>
In order for the jenkins user to restart the web server, he needs to be given the appropriate rights:
su cat > /etc/sudoers << EOF jenkins ALL=(ALL) NOPASSWD: /etc/init.d/apache2 EOF exit
To run the tests, create a wrapper script that will set the necessary environment variables and translate the command line parameters to the Selenium server through itself:
cd /var/lib/jenkins/tools/SeleniumRC touch selenium.sh chmod +x selenium.sh cat > selenium.sh << EOF
Configure Apache. Edit the /etc/apache/conf.d/mod_mono file and specify the location of the application:
<IfModule !mod_mono.c> LoadModule mono_module /usr/lib/apache2/mod_mono.so </IfModule> MonoAutoApplication disabled AddHandler mono .aspx .ascx .asax .ashx .config .cs .asmx .axd MonoApplications "/:/home/vm/public_html" AddType application/x-asp-net .aspx AddType application/x-asp-net .asmx AddType application/x-asp-net .ashx AddType application/x-asp-net .asax AddType application/x-asp-net .ascx AddType application/x-asp-net .soap AddType application/x-asp-net .rem AddType application/x-asp-net .axd AddType application/x-asp-net .cs AddType application/x-asp-net .vb AddType application/x-asp-net .master AddType application/x-asp-net .sitemap AddType application/x-asp-net .resources AddType application/x-asp-net .skin AddType application/x-asp-net .browser AddType application/x-asp-net .webinfo AddType application/x-asp-net .resx AddType application/x-asp-net .licx AddType application/x-asp-net .csproj AddType application/x-asp-net .vbproj AddType application/x-asp-net .config AddType application/x-asp-net .Config AddType application/x-asp-net .dll DirectoryIndex index.aspx DirectoryIndex Default.aspx DirectoryIndex default.aspx
And create the application configuration file /etc/apache2/conf.d/Example: Alias / "home/vm/public_html" MonoServerPath Example "/usr/bin/mod-mono-server2" MonoSetEnv Example MONO_IOMAP=all MonoApplications Example "/:/home/vm/public_html" <Location "/"> Allow from all Order allow,deny MonoSetServerAlias Example SetHandler mono SetOutputFilter DEFLATE SetEnvIfNoCase Request_URI "\.(?:gif|jpe?g|png)$" no-gzip dont-vary </Location>
su cat > /etc/sudoers << EOF jenkins ALL=(ALL) NOPASSWD: /etc/init.d/apache2 EOF exit
Configure the Selenium plugin:
Sample report (Jenkins simply displays the Selenium report one-to-one):
This completes the formation of the NAnt script.10. As well as the task of obtaining source code from the repository, the task of scanning the code for open tasks is also called directly from Jenkins (bypassing the Nant script).Configure the Task Scanner plugin:
Report example: The
assembly project is configured and ready to run.Tuning
Literally in a nutshell I would like to highlight some other plugins (of which there is a huge amount ).Backup - the purpose of the plugin is obvious from its name, and its configuration is trivial. Its description is unnecessary, since Backup is the very first thing to worry about!JobConfigHistory - in the course of setting up, the changes made to the project configuration turn out to be unsuccessful and in order to return to the previous version easily, you must take steps to save the previous version yourself. This plugin keeps a history of changes and allows you to easily identify the changes made.Green balls- by default, Jenkins uses three colors to display the status: red, yellow and blue. This plugin allows you to replace blue with green. The practical value of this plugin is highly questionable, but the aesthetic is hard to overestimate!Next Build Number - allows you to set the number of the next build. It is convenient in cases where several assemblies are performed during tuning, which are then deleted, and a hole is formed in the numbering. Or in those cases when it is necessary to force a version number (for example, for a release).Sidebar-link- a very curious plugin. Allows you to place links on the main page or on the pages of projects. When it can be useful. For example, on the main page you can place a link to some corporate resource, knowledge base or something else (do not forget that the content placed in the userContent directory is displayed by Jenkinso automatically). To create a link on the main page, you need to configure the server (and non-project):
As a result, the Important link appears on the main page:
On the project page, you can place a link to a resource specific to this project (for example, to an svn repository), or, which may be more useful, to a report of some utility for which there is no corresponding Jenkins plugin. To create a link on the project page, you need to configure it:
Please note that the icon files can be uploaded to the server only through the server settings, this function is not available in the project settings.
This is what the Subversion link will look like on the project page.This is how the project page will look like in conclusion:
This is the build report page:
Extensive reasoning (instead of a normal conclusion)
Of course, this example is idealized.Firstly: the presented example does not contain a database, which is extremely rare in life and deprives the assembly project of an entertaining task of maintaining the database in the correct state (either always to collect it from scripts under control, or to control directly the binary file, then it is possible to roll controlled scripts on a binary file).Secondly: assembling on CI Servere very often may not be enough, in most cases it is advisable to create a Matrix project, so the operation of deploying an application may be somewhat more difficult.Thirdly: Unit tests are probably more correctly performed in a test environment, and not on a build server.In the example, none of the notification plug-ins is considered. In practice, their use may be necessary.In the end, on the CI Servere may not be functional tests run mechanism of the X-server in this case will change a little ( on when the measures ).What would like more.Most want Pre-Tested Commit .I would like a code coverage analyzer tests.I really want a metrics collector with broader parameters. The number of lines of code written in C # is certainly cool, but I would like to see information about the cyclomatic complexity and the degree of connectivity, and perhaps about anything else. By the way, the default IDE copes with the task of collecting metrics much better than the utility presented in the application. On the Metrics Monodevelop tab, you can see the following information:
PS
Well, at the very end, I would like to invite all those who prefer to learn about errors not one month after the commit from the customer, but the next day from the build server, share their experience and make comments to the presented example.