понедельник, 18 июля 2011 г.

Visual Builds Board



<jenkinsDashboardSection uri="http://jenkinsmaster-hv:8080" interval="0:05:00">
              <forceBuild
                     uri="http://jenkinsmaster-hv:8080/job/BuildBranch/build?delay=0sec"
                     body="name=BRANCH_TO_BUILD&amp;value=$1&amp;json=%7B%22parameter%22%3A+%7B%22name%22%3A+%22BRANCH_TO_BUILD%22%2C+%22value%22%3A+%22$1%22%7D%7D&amp;Submit=Build" />
              <avatars users="http://plan.tpondemand.com/api/v1/Users?include=[id,email]&amp;take=1000&amp;token=zzzzzzzzzzzzzz" avatar="http://plan.tpondemand.com/avatar.ashx?size=32&amp;UserId={0}"/>
              <branchTitle
                     namePattern="(?:US|Bug)#?(?&lt;number&gt;\d+).*"
                     titlePattern="\[&quot;(.*?)&quot;\]"
                     title="$1"
sourceUri="http://plan.tpondemand.com/api/v1/Assignables/${number}?include=[Name]&amp;format=array&amp;token=zzzzzzzzzzzzzzz"               externalUri="http://plan.tpondemand.com/View.aspx?ID=${number}"
                     />
              <!---->
              <monitoredJobs>
                     <job name="BuildAll"/>
                     <job name="BuildCommit"/>
                     <job name="BuildBranchUnitTestsOnly"/>
                     <job name="BuildBranch"/>
                     <job name="FastBuildBranch"/>
                     <job name="NightlyMasterBuild"/>
              </monitoredJobs>
              <buildParts>
                     <part name="Unit Tests">
                           <job name="BuildUnitTests" />
                           <job name="UnitTestPart0"/>
                           <job name="UnitTestPart1"/>
                           <job name="UnitTestPart2"/>
                           <job name="UnitTestPart3"/>
                           <job name="UnitTestPart4"/>
                           <job name="UnitTestPart5"/>
                           <job name="UnitTestPart6"/>
                           <job name="UnitTestPart7"/>
                           <job name="UnitTestPartOther"/>
                     </part>
                     <part name="Plugins" mode="FailOnly">
                           <job name="BuildPluginsUnitTests" />
                     </part>
                     <part name="Build" mode="FailOnly"  aggregation="Optimistic">
                           <job name="BuildPackage" />
                           <job name="BuildApplication" />
                     </part>
                     <part name="F00" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart0"/>
                           <job name="FastFuncTestPart0"/>
                     </part>
                     <part name="F01" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart1"/>
                           <job name="FastFuncTestPart1"/>
                     </part>
                     <part name="F02" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart2"/>
                           <job name="FastFuncTestPart2"/>
                     </part>
                     <part name="F03" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart3"/>
                           <job name="FastFuncTestPart3"/>
                     </part>
                     <part name="F04" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart4"/>
                           <job name="FastFuncTestPart4"/>
                     </part>
                     <part name="F05" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart5"/>
                           <job name="FastFuncTestPart5"/>
                     </part>
                     <part name="F06" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart6"/>
                           <job name="FastFuncTestPart6"/>
                     </part>
                     <part name="F07" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart7"/>
                           <job name="FastFuncTestPart7"/>
                     </part>
                     <part name="F08" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart8"/>
                           <job name="FastFuncTestPart8"/>
                     </part>
                     <part name="F09" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart9"/>
                           <job name="FastFuncTestPart9"/>
                     </part>
                     <part name="F10" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart10"/>
                           <job name="FastFuncTestPart10"/>
                     </part>
                     <part name="F11" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart11"/>
                           <job name="FastFuncTestPart11"/>
                     </part>
                     <part name="F12" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart12"/>
                           <job name="FastFuncTestPart12"/>
                     </part>
                     <part name="F13" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPart13"/>
                           <job name="FastFuncTestPart13"/>
                     </part>
                     <part name="FOt" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPartOther"/>
                           <job name="FastFuncTestPartOther"/>
                     </part>
                     <part name="FI" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestIntegration"/>
                           <job name="FastFuncTestPartIntegration"/>
                     </part>
                     <part name="FV" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPartViews"/>
                           <job name="FastFuncTestPartViews"/>
                     </part>
                     <part name="FP1" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPluginsPart1" />
                           <job name="FastFuncTestPluginsPart1" />
                     </part>
                     <part name="FP2" mode="FailOnly" aggregation="Optimistic">
                           <job name="FuncTestPluginsPart2" />
                           <job name="FastFuncTestPluginsPart2" />
                     </part>


                     <part name="UFT" mode="Unimportant">
                           <job name="FuncTestPartUnstable"/>
                           <job name="FastFuncTestPartUnstable"/>
                           <job name="FuncTestPluginsUnstable"/>
                           <job name="FastFuncTestPluginsUnstable"/>
                     </part>
                     <part name="CC" mode="Unimportant">
                           <job name="CodeCoverage"/>
                     </part>
              </buildParts>
       </jenkinsDashboardSection>



Xpath Description Sample
@uri Root uri for Jenkins http://jenkinsmaster-hv:8080
@interval Pool interval 0:05:00
forceBuild/@uri Link for "Force Build" button (actually, run the specific job with given parameters) http://jenkinsmaster-hv:8080/job/BuildBranch/build?delay=0sec
forceBuild/@body Body of POST request for "Force Build button". $1 is a placeholder for the build name
avatars  Section to get avatars for changes (now are hardcoded for @TargetProcess.com domain)
branchTitle Settings to get branch descriptions from TP
branchTitle/@namePattern Regex for Git branch name (?:US|Bug)#?(?&lt;number&gt;\d+).*
branchTitle/@sourceUri Uri to TP Rest api to get an assignable name. Use placeholders defined in @namePattern http://plan.tpondemand.com/api/v1/Assignables/${number}?include=[Name]&amp;format=array&amp;token=zzzz"
branchTitle/@titlePattern How to get title from @sourceUri response \[&quot;(.*?)&quot;\]
branchTitle/@title  Title to display. Use placeholders from @titlePattern $1
branchTitle/@externalUri Uri for links on title. Use placeholders from @namePattern http://plan.tpondemand.com/View.aspx?ID=${number}
monitoredJobs/job/@name List of root jobs to monitor
buildParts/part Definition of single bubble on a build
buildParts/part/@name Name of bubble
buildParts/part/job/@name Jobs to include to the bubble
buildParts/part/@mode  How bubble change the color of entire build (FailOnly - only red color is used, Unimportant - do not use the bubble color, Normal (default) - use red and yellow color).
buildParts/part/@aggregation How bubble color is calculated. Optimistic - use "the best" status. Pessimistic (default) - use "the worst" status. 

The dashboard is designed to show hierarchic jobs. For example, in our case we have the following hierarchy:


  • BuildAll
    • BuildUnitTests
      • UnitTestsPart1
      • ...
      • UnitTestsPart7
    • BuildApplication
      • FastFuncTestPart1
      • ...
      • FastFuncTestPart15
    • BuildPacakage

суббота, 9 июля 2011 г.

NBehave will be capable running text scenarios as in our dev.process soon!

Some time ago we agreed that we can post a patch to NBehave, so I did.

Today this patch was approved in almost exact form as we use it in our dev.process


Congratulation, guys! All our experience of using BDD specs will be spread among people who missed it! :)

среда, 6 июля 2011 г.

Entity change-tracking with NHibernate

Hi,

here is a tip on entity change-tracking with NHibernate. NHibernate session tracks all of the objects associated with it, thus it's possible not only to determine if entity has been changed, but also if particular property has been changed as well as to get its old value. The following snippet demonstrates this functionality:

public static bool PropertyIsDirty(this ISession session, object entity, string propertyName)
{
var className = NHibernateProxyHelper.GuessClass(entity).FullName;
var sessionImpl = session.GetSessionImplementation();
var persister = sessionImpl.Factory.GetEntityPersister(className);
var oldEntry = sessionImpl.PersistenceContext.GetEntry(sessionImpl.PersistenceContext.Unproxy(entity));
var oldState = oldEntry.LoadedState;
var currentState = persister.GetPropertyValues(entity, sessionImpl.EntityMode);
var dirtyProperties = persister.FindDirty(currentState, oldState, entity, sessionImpl);
var index = Array.IndexOf(persister.PropertyNames, propertyName);
var isDirty = dirtyProperties != null && Array.IndexOf(dirtyProperties, index) != -1;

return isDirty;
}
public static object GetOriginalEntityPropertyValue(this ISession session, object entity, string propertyName)
{
var className = NHibernateProxyHelper.GuessClass(entity).FullName;
var sessionImpl = session.GetSessionImplementation();
var persister = sessionImpl.Factory.GetEntityPersister(className);
var oldEntry = sessionImpl.PersistenceContext.GetEntry(sessionImpl.PersistenceContext.Unproxy(entity));
var oldState = oldEntry.LoadedState;
var currentState = persister.GetPropertyValues(entity, sessionImpl.EntityMode);
var dirtyProperties = persister.FindDirty(currentState, oldState, entity, sessionImpl);
var index = Array.IndexOf(persister.PropertyNames, propertyName);
var isDirty = (dirtyProperties != null) ? (Array.IndexOf(dirtyProperties, index) != -1) : false;

return isDirty ? oldState[index] : currentState[index];
}