Imagine situation when you have already defined model with predefined db index. Like PriceRowModel:

<itemtype code="PriceRow" autocreate="true" generate="true">
   (...)
   <indexes>
      <index name="unique_listprice" unique="true">
         <key attribute="field1"/>
         <key attribute="field2"/>
      </index>
   </indexes>
</itemtype>

Your system is already on production and you have a lot of values inside this table. Then you need to extend the model and create new table, but with different index.

<itemtype code="NewPriceRow" autocreate="true" generate="true">
   (...)
   <indexes>
      <index name="unique_listprice" unique="true">
         <key attribute="field1"/>
         <key attribute="field3"/>
      </index>
   </indexes>
</itemtype>

Like you can see I’ve tried to redefine index unique_listprice. But the result was that old index was created in old version, and the new one was not created at all.

To workaround this situation we need to move unique_listprice to upper abstract class and set autocreate and generate flag to false. Our new working xml will look like this:

<itemtype code="PriceRow" autocreate="false" generate="false">
   (...)
   <!-- indexes element removed -->
</itemtype>
 
<itemtype code="CustomPriceRow" extends="PriceRow" autocreate="true" generate="true">
   (...)
   <indexes>
      <index name="unique_listprice" unique="true">
         <key attribute="field1"/>
         <key attribute="field2"/>
      </index>
   </indexes>
</itemtype>
 
<itemtype code="NewPriceRow" extends="PriceRow" autocreate="true" generate="true">
    (...)
    <indexes>
        <index name="unique_listprice" unique="true">
            <key attribute="field1"/>
            <key attribute="field3"/>
        </index>
    </indexes>
</itemtype>

You can see discussion around this topic in hybris experts community.

Stash-plugin-issues

In my current Hybris project one of coding standard is to publish SonarQube report before every push to master. This rule is nice, but not always everyone fallows it.

This is why I’ve wanted to introduce plugin that can automatically generates SonarQube analysis results in BitBucket (Stash) pull-request. And I’ve found it: SonarQube Stash (BitBucket) plugin.

The workflow looks as fallow:

user creates pull-request 
-> hook executes Jenkins job 
-> sonar-scanner executes analysis in preview mode 
-> Executing post-job org.sonar.plugins.stash.StashIssueReportingPostJob
-> SonarQube analysis overview has been reported to Stash.

It’s almost perfect, but instead of comments in lines with violations I get a lot of messages like this:

Comment "squid:S1134" cannot be pushed to Stash like it does not belong to diff view - nc3cockpit/src/com/nespresso/nc3/cockpit/components/header/Nc3LeftSectionHeaderComponent.java (line: 14)

How to fix “Comment cannot be pushed to Stash like it does not belong to diff view”

In my case the problem was with project configuration. Analysed code was in different location then GIT root directory:

/
/README.md
/src
/src/sonar-project.properties
/src/lib
/src/lib/sonar-project.properties
/src/web
/src/web/sonar-project.properties
/docs

Similar structure can be checked here: https://github.com/kirkor/sonar-stash-test-project/tree/0646de81f2424061ff2deaeec4899ee4cd356cbb

Note that I’m referring to old version of this repo where this problem exists. In the newest revision whole project is configured in a way that problem “Comment cannot be pushed” is not occurring.

I’m executing sonar-scanner from Jenkins, so the working directory is ./ instead of ./src/. This is why my command was like this:

sonar-scanner sonar.projectBaseDir=./src/

and main sonar-project.properties:

sonar.modules=lib,webapp

Results

Full path to file:

E:/Jenkins/workspace/CI03/src/lib/src/main/java/pl/com/bernas/sonar/stash/test/lib/DummyService.java

Output:

./lib/src/main/java/pl/com/bernas/sonar/stash/test/lib/DummyService.java

Should be:

./src/lib/src/main/java/pl/com/bernas/sonar/stash/test/lib/DummyService.java

The Fix

Move your main sonar-project.properties file from ./src/ to ./, change sonar-project.properties into:

sonar.modules=src/lib,src/webapp

execute command:

sonar-scanner sonar.projectBaseDir=./

AND IT’S WORKING :)

Stash-plugin-task

During development of my fix PR#56 (which is not need eventually), I created GIT repo to test the solution. If you fallow those two links you can find some more interesting things how it’s working.

And it’s all started from Issue: Comment “xxx” cannot be pushed to Stash like it does not belong to diff view.

Untitled

How to add Groovy and Spock to your Hybris extension.

My goal is to develop new features for our eCommerce solution with TDD methodology. To achieve that I want to use fancy technologies: Groovy and Spock.

Hybris uses ant, and don’t have direct support for Spock, but has for Groovy. To introduce this framework to your Hybris 5.4, please fallow those steps:

General advice, read my comments in code listing.

Prerequirements:

Make sure, you configure groovy extensions in your hybris instance. To check this, please go to hybris\config\localextensions.xml and look for two entries:

<hybrisconfig (...)>
	<extensions>
		(...)
		<extension dir="${HYBRIS_BIN_DIR}/ext-platform-optional/ygroovy" />
		<extension dir="${HYBRIS_BIN_DIR}/ext-platform-optional/groovynature" />
		(...)
	</extensions>
</hybrisconfig>

Step 1

Configure your extension to use maven and add groovy (EXTENSION_PATH/extensioninfo.xml):

<extensioninfo>
    <extension (...) usemaven="true">
        <requires-extension name="groovynature"/>
		(...)
    </extension>
</extensioninfo>

Step 2

This step is needed if you didn’t create extension with groovy nature.

Add missing ant macrodef, for your extension (EXTENSION_PATH/buildcallbacks.xml):

<project name="EXTENSION_NAME_buildcallbacks">    
	<macrodef name="EXTENSION_NAME_before_build">
        <sequential>
            <!-- defines native file extension used by the nature of the extension -->
            <property name="ext.EXTENSION_NAME.native.file.extension" value="groovy"/>
            <!-- defines source folder for groovy files -->
            <property name="ext.EXTENSION_NAME.additional.src.dir" value="groovysrc"/>
            <!-- defines test source folder for groovy tests -->
            <property name="ext.EXTENSION_NAME.additional.testsrc.dir" value="groovytestsrc"/>
            <outofdate>
                <sourcefiles>
                    <fileset dir="${ext.EXTENSION_NAME.path}">
                        <include name="${ext.EXTENSION_NAME.additional.src.dir}/**"/>
                    </fileset>
                </sourcefiles>
                <targetfiles path="${HYBRIS_TEMP_DIR}/touch/EXTENSION_NAME_srctouch"/>
                <sequential>
                    <touch mkdirs="true">
                        <fileset
                                dir="${ext.EXTENSION_NAME.path}/${ext.EXTENSION_NAME.additional.src.dir}"/>
                    </touch>
                </sequential>
            </outofdate>
            <outofdate>
                <sourcefiles>
                    <fileset dir="${ext.EXTENSION_NAME.path}">
                        <include name="${ext.EXTENSION_NAME.additional.testsrc.dir}/**"/>
                    </fileset>
                </sourcefiles>
                <targetfiles path="${HYBRIS_TEMP_DIR}/touch/EXTENSION_NAME_testsrctouch"/>
                <sequential>
                    <touch mkdirs="true">
                        <fileset
                                dir="${ext.EXTENSION_NAME.path}/${ext.EXTENSION_NAME.additional.src.dir}"/>
                        <fileset
                                dir="${ext.EXTENSION_NAME.path}/${ext.EXTENSION_NAME.additional.testsrc.dir}"/>
                    </touch>
                </sequential>
            </outofdate>
        </sequential>
    </macrodef>

    <macrodef name="EXTENSION_NAME_after_compile_core">
        <sequential>
            <groovynature_compile_core extname="EXTENSION_NAME"/>
        </sequential>
    </macrodef>
    (...)
</project>

Step 3

Add required dependencies to your extension (EXTENSION_PATH/external-dependencies.xml):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	(...)
	<dependencies>
		<!-- TESTING -->
		<dependency>
			<groupId>org.spockframework</groupId>
			<artifactId>spock-core</artifactId>
			<version>1.0-groovy-2.3</version><!-- Hybris 5.4 depends on Groovy 2.3, so we are obligated to use this version -->
			<scope>test</scope>
		</dependency>
		<!-- Optional dependencies for using Spock -->
		<!-- use a specific Groovy version rather than the one specified by spock-core -->
		<!-- already in hybris
		<dependency>
			<groupId>org.codehaus.groovy</groupId>
			<artifactId>groovy-all</artifactId>
			<version>2.3.1</version>
		</dependency>-->
		 
		<dependency> <!-- enables mocking of classes (in addition to interfaces) -->
			<groupId>cglib</groupId>
			<artifactId>cglib-nodep</artifactId>
			<version>3.1</version>
			<scope>test</scope>
		</dependency>
		 
		<dependency> <!-- enables mocking of classes without default constructor (together with CGLIB) -->
			<groupId>org.objenesis</groupId>
			<artifactId>objenesis</artifactId>
			<version>2.1</version>
			<scope>test</scope>
		</dependency>
		 
		<dependency> <!-- only required if Hamcrest matchers are used -->
			<groupId>org.hamcrest</groupId>
			<artifactId>hamcrest-core</artifactId>
			<version>1.3</version>
			<scope>test</scope>
		</dependency>
		 
		<dependency>
			<groupId>org.ow2.asm</groupId>
			<artifactId>asm</artifactId>
			<version>5.0.3</version><!-- watch out for this one! -->
		</dependency>
	</dependencies>
</project>

Run maven to update your new dependencies:

hybris\bin\platform> ant updateMavenDependencies

Maven should download all your new dependencies into EXTENSION_PATH/lib folder.

Step 4

Replace old ASM library with newer. Spock requires this change.

Replace: hybris/bin/platform/ext/core/lib/asm-3.3.1.jar with asm-5.0.3.jar.

You can find this JAR in your EXTENSION_PATH/lib folder.

Step 5

Create your firs Spock Specification in folder EXTENSION_PATH/groovytestsrc.

package pl.com.bernas.hybris.groovy

import de.hybris.bootstrap.annotations.UnitTest
import org.junit.Test
import spock.lang.Specification

/**
 * IMPORTANT!
 * @UnitTest is really important for Hybris to know when this test should be executed.
 * Without any of de.hybris.bootstrap.annotations.* annotation, test mechanism will not pick up this specification.
 *
 * Created by kirkor on 7/25/2016.
 */
@UnitTest
class SimpleStringComparatorSpec extends Specification {

    /**
     * IMPORTANT!
     * If a test class don't have at least one test annotation,
     * TestClassesUtil will ommit this test and it will not be executed.
     */
    @Test
    def "should concatenate two strings into one"() {
        given:
            String test = "I have a dog"
        when:
            test += " and two cats."
        then:
            test == "I have a dog and two cats."
    }
}

Testing…

hybris\bin\platform> setantenv.bat
hybris\bin\platform> cd ..\custom\EXTENSION
hybris\bin\custom\EXTENSION> ant build
(...)
build:
 [echo] preparing...
 [echo] building extension 'EXTENSION'...
(...)
  [groovyc] Compiling 1 source files to hybris\bin\custom\EXTENSION\classes
[testClassesScanner] Found 1 EXTENSION testclasses in 14.25 ms
BUILD SUCCESSFUL
Total time: 10 seconds
hybris\bin\custom\EXTENSION> ant unittests -Dtestclasses.packages=pl.com.bernas.*
 (...)
 [echo] preparing...
 [echo] Annotations : unittests
 [echo] Extensions  : EXTENSION
 [echo] Packages(+) : pl.com.bernas.*
 [echo] Packages(-) :
 [echo] JUnit Split :
 [echo] Web         : false
 (...)
|-- Adding Filter for package pl.com.bernas.*
|-- Adding Filter for UnitTests
|-- Adding Filter for extension EXTENSION
 [yunitint] Using TestClassesUtil...
 [yunitint] Found 1 filtered classes...
 [yunitint] Scanning finished in : 337ms, found 1 testclasse(s)!
 [yunitint] --> found 1 testclasses!
 (...)
 [yunitint] Running pl.com.bernas.hybris.groovy.SimpleStringComparatorSpec
 [yunitint] INFO  [main] (junit) [SimpleLog4jPerformanceMeasurement] Test method pl.com.bernas.hybris.groovy.SimpleStringComparatorSpec.should concatenate two strings into one succeeded. Time taken: 181.5 ms
 [yunitint] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.636 sec
 (...)
     [echo] Report generated to src/hybris/log/junit/index.html

What we just achieve is the possibility of running together, the old JUnit tests and Spock Specification. This is because Spock is build on top of JUnit, as a Runner.

This is extremely useful if we already have some test in JUnit, but we want to add new with Spock, and run them from command line on Jenkins or Bamboo – to have one big report about our tests.