Structure101 Build and the Structure101 SonarQube plugin can be incorporated into your existing Jenkins CI process. This post describes the necessary configuration. [Build 14507 and later of the Structure101 SonarQube plugin]

Structure101 Build performs architectural checks and can publish a snapshot and the architectural diagrams to a Structure101 repository. The Check Key Measures and Check Spec operations can be configured to fail the build directly, by throwing a run time exception, or indirectly using Jenkins build steps to set the build status.

The SonarQube plugin defines seven new rules of type code smell: –
  • Packages should not be Fat
  • Classes should not be Fat
  • Methods should not be Fat
  • Packages should not contain tangled sub-packages
  • Dependencies should comply with the Structure Spec
  • Items should not exist in a specified scope unless they are included in the Structure Spec
  • Dependencies should comply with all enforced Architecture Diagrams
If any of the above are found a SonarQube Issue is created. These issues will be reported as new according to your project’s Leak Period configuration.
The plugin uses the output file from the Structure101 Build check-key-measures operation. So this must be configured to run before the SonarQube analysis.

 

Installing and Configuring the SonarQube Plugin

The Structure101 SonarQube plugin jar file should be copied into the extensions/plugins folder of the SonarQube installation. Any previous version of the Structure101 plugin should be removed and the SonarQube instance restarted.

Create a new Quality Profile with language Java

 

Change the parent to your existing Java quality profile

Click Activate More to add the Structure101 rules

Filter the rules using Java language and Structure101 repository

Activate each of the rules setting the desired severity

Jenkins Prerequisites

The examples described use several Jenkins plugins that are not installed by default. Check your Jenkins configuration and install any that are missing.

Overview of the Build Steps

The build steps are: –

  1. Execute the compile/test phase
  2. If the build is successful
    1. Update the Structure101 Build configuration file with the label of the current build
    2. Run the Structure101 Build process
      1. Check Key Measures
      2. Check Spec
      3. Publish
      4. Report Summary
  3. Run the SonarQube Scanner
  4. If Check Key Measures or Spec Check failed
    1. Mark the build unstable/failed
  5. If the build is successful
    1. Update the Structure101 Build configuration baseline property
    2. Commit/push the updated Build configuration file

The baseline property in the check-key-measures and check-spec operations is always set to the label of the last build that did not fail the checks. This allows the snapshot to be published on every build, even those that fail the checks. The snapshots capture the model and diagrams for each build and allow visual comparisons between them.

Initial Publish of Snapshot

The Structure101 project must be published to the Structure101 Repository before the Jenkins driven publish operation can run. The label used for this initial snapshot should be added to the structure101-build-config.xml file in the baseline property of the check-key-measures, check-spec and check-architecture operations.

For multiple branches either use different Structure101 project names for each branch or use the same project name and a branch identifier in the label argument of the publish operation.

Build Steps in Detail – Maven

This first example uses the Maven Integration plugin

This plugin adds a Maven Build Step with Pre and Post Steps. No Pre Steps are used in the example. The Post Steps are configured to run only if the build succeeds.

 

The first of the post steps is an execute shell command

This step updates the Structure101 Build configuration file with the label of the current build and runs the Structure101 Build process.

The awk command replaces the text LABEL_TOKEN with the content of the build_tag variable. In this case a concatenation of the system variables GIT_BRANCH and BUILD_ID separated by an underscore

The LABEL_TOKEN value is used for the label argument of the publish operation in the structure101-build-config.xml file.

<operation type="publish">
    <argument name="label" value="LABEL_TOKEN"/>
    <argument name="diagrams" value="true"/>
    <argument name="spec" value="true"/>
    <argument name="actions" value="true"/>
</operation>
awk -v build_tag="${GIT_BRANCH}_$BUILD_ID" '{gsub("LABEL_TOKEN", build_tag)}1' structure101-build-config.xml > labelled-structure101-build-config.xml

 

The updated file is passed to the Structure101 Build command

java -jar /opt/structure101-build-java-all-5.0.14435/structure101-java-build.jar labelled-structure101-build-config.xml -licenseDir=/opt/structure101-build-license

 

And finally the working file is removed

rm labelled-structure101-build-config.xml

 

The second step runs the SonarQube scanner using the Maven goal in an Invoke top-level Maven targets step. Note that the new SonarQube plugin does not require any property definition in the Maven pom.xml. But the plugin does require a system property to be set that provides the path to the output file of the check-key-measures operation run in the previous step. This property is available to the Structure101 plugin when SonarQube invokes its scan.

The path must match that set in the structure101-build-config.xml file

 <operation type="check-key-measures">
<argument name="output-file" value="const(THIS_FILE)/target/structure101/key-measures.xml"/>
<argument name="output-file-for-snapshot" value="const(THIS_FILE)/s101working/structure101report/snapshot-key-measures.xml"/>
<argument name="baseline" value="14"/>
<argument name="useProjectFileSpec" value="true"/>
<argument name="useProjectFileDiagrams" value="true"/>
<argument name="fail-on-architecture-violations" value="false"/>
<argument name="fail-on-fat-package" value="false"/>
<argument name="fail-on-fat-class" value="false"/>
<argument name="fail-on-fat-method" value="false"/>
<argument name="fail-on-feedback-dependencies" value="false"/>
<argument name="fail-on-spec-violation-dependencies" value="false"/>
<argument name="fail-on-total-problem-dependencies" value="false"/>
<argument name="fail-on-spec-item-violations" value="false"/>
<argument name="fail-on-biggest-class-tangle" value="false"/>
<argument name="fail-on-tangled-package" value="false"/>
<argument name="fail-on-architecture-violations" value="false"/>
<argument name="identifier-on-violation" value="S101 key measure violation"/>
</operation>

 

The next step is a Conditional step (single) that uses Text Finder to check the console output for failure messages from the check-key-measures operation and the Set the build result step to set the build status if any are found. In this example the build is set to failed if any of the messages are detected using a simple OR’d regex

The messages are: –

FAIL! fat0 has increased by 
FAIL! fat1 has increased by
FAIL! fat2 has increased by
FAIL! feedbackDependencies has increased by
FAIL! specViolationDependencies has increased by
FAIL! totalProblemDependencies has increased by
FAIL! specItemViolations has increased by
FAIL! biggestClassTangles has increased by
FAIL! tangledDesign has increased by
FAIL! numViolations has increased by

if desired a different build status can be set for the messages by creating multiple Text Finder steps.

 

The next step is also a single conditional that only runs if the build is successful. It executes a shell command that updates the baseline argument of the check-key-measures, check-spec and check-architecture operations in the structure101-build-config.xml file and then commits the changes.

The awk command replaces the line containing the baseline argument with the content of the baseline_tag variable. This should be identical to the variable used to set the label argument.

awk -v baseline_tag="\<argument name\=\"baseline\" value\=\"${GIT_BRANCH}_$BUILD_ID\"/\>" '{gsub("\<argument name=\"baseline\" value\=\".*", baseline_tag)}1' structure101-build-config.xml > baseline-structure101-build-config.xml 
mv -f baseline-structure101-build-config.xml structure101-build-config.xml 
git commit -am "Increment baseline label"

Finally the Git Publisher Post-build Action is used to push the baseline change to the repository.

Build Steps in Detail – Gradle

The gradle example uses a Freestyle project. The steps are all configured as Build Steps.

The Invoke Gradle Script step is followed by a Conditional step (single) that runs only if the build is successful.

This step updates the Structure101 Build configuration file with the label of the current build and runs the Structure101 Build process.

The awk command replaces the text LABEL_TOKEN with the content of the build_tag variable. In this case a concatenation of the Jenkins variables BRANCH_NAME and BUILD_ID

The LABEL_TOKEN value is used for the label argument of the publish operation in the structure101-build-config.xml file.

<operation type="publish">
    <argument name="label" value="LABEL_TOKEN"/>
    <argument name="diagrams" value="true"/>
    <argument name="spec" value="true"/>
    <argument name="actions" value="true"/>
</operation>
awk -v build_tag="$BRANCH_NAME$BUILD_ID" '{gsub("LABEL_TOKEN", build_tag)}1' structure101-build-config.xml > labelled-structure101-build-config.xml

 

The updated file is passed to the Structure101 Build command

java -jar /opt/structure101-build-java-all-5.0.14435/structure101-java-build.jar labelled-structure101-build-config.xml -licenseDir=/opt/structure101-build-license

 

And finally the working file is removed

rm labelled-structure101-build-config.xml

 

The next step runs the SonarQube scanner using  an Invoke Gradle script step. Note that the new SonarQube plugin does not require any property definition in the build.gradle file. But the plugin does require a system property to be set that provides the path to the output file of the check-key-measures operation run in the previous step. This property is available to the Structure101 plugin when SonarQube invokes its scan.

The path must match that set in the structure101-build-config.xml file

 <operation type="check-key-measures">
<argument name="output-file" value="const(THIS_FILE)/target/structure101/key-measures.xml"/>
<argument name="output-file-for-snapshot" value="const(THIS_FILE)/s101working/structure101report/snapshot-key-measures.xml"/>
<argument name="baseline" value="14"/>
<argument name="useProjectFileSpec" value="true"/>
<argument name="useProjectFileDiagrams" value="true"/>
<argument name="fail-on-architecture-violations" value="false"/>
<argument name="fail-on-fat-package" value="false"/>
<argument name="fail-on-fat-class" value="false"/>
<argument name="fail-on-fat-method" value="false"/>
<argument name="fail-on-feedback-dependencies" value="false"/>
<argument name="fail-on-spec-violation-dependencies" value="false"/>
<argument name="fail-on-total-problem-dependencies" value="false"/>
<argument name="fail-on-spec-item-violations" value="false"/>
<argument name="fail-on-biggest-class-tangle" value="false"/>
<argument name="fail-on-tangled-package" value="false"/>
<argument name="fail-on-architecture-violations" value="false"/>
<argument name="identifier-on-violation" value="S101 key measure violation"/>
</operation>

 

The next step is a Conditional step (single) that uses Text Finder to check the console output for failure messages from the check-key-measures operation and the Set the build result step to set the build status if any are found. In this example the build is set to failed if any of the messages are detected using a simple OR’d regex.

The messages are: –

FAIL! fat0 has increased by 
FAIL! fat1 has increased by
FAIL! fat2 has increased by
FAIL! feedbackDependencies has increased by
FAIL! specViolationDependencies has increased by
FAIL! totalProblemDependencies has increased by
FAIL! specItemViolations has increased by
FAIL! biggestClassTangles has increased by
FAIL! tangledDesign has increased by
FAIL! numViolations has increased by

if desired a different build status can be set for the messages by creating multiple Text Finder steps.

 

The next step is also a single conditional that only runs if the build is successful. It executes a shell command that updates the baseline argument of the check-key-measures, check-spec and check-architecture operations in the structure101-build-config.xml file and then commits the changes.

The awk command replaces the line containing the baseline argument with the content of the baseline_tag variable. This should be identical to the variable used to set the label argument.

awk -v baseline_tag="\<argument name\=\"baseline\" value\=\"$BRANCH_NAME$BUILD_ID\"/\>" '{gsub("\<argument name=\"baseline\" value\=\".*", baseline_tag)}1' structure101-build-config.xml > baseline-structure101-build-config.xml 
mv -f baseline-structure101-build-config.xml structure101-build-config.xml 
git commit -am "Increment baseline label"

Finally the Git Publisher Post-build Action is used to push the baseline change to the repository.

 

Process Considerations

The automated update of the baseline version is critical to the success of the process. For this reason it is suggested that that updates to the structure101-build-config.xml file are carefully controlled. After the initial publish further manual publishing of snapshots to the Structure101 repository is not recommended.

Forcing Success for a Build Failing the Structure101 Checks

It may be necessary to force the success of a failing build. This can be achieved by manually updating the baseline arguments in the structure101-build-config.xml file to the label of the last failed build. The violations causing the failure will no longer be treated as new and the build will succeed.

Updating the Structure Spec or Diagrams

The process for updating (or creating new) architecture diagrams or structure spec is simply to commit the modifed java.hsp file to source control. The next Jenkins build will check out the updated file and perform the check operations using the local spec and architecture diagrams in the Structure101 project file. The properties useProjectFileSpec and useProjectFileDiagrams force this behaviour.

Potential Problems

The Structure101 Groups are not displaying in the Measures Page

The Structure101 Quality Profile is not configured for the SonarQube project. Update the project configuration.

The SonarQube scanner is not configured with the structure101.reportdir system property or it does not match the output-file property of the check-key-measures operation. Check the build log for error messages and update the build config file and Jenkins SonarQube step to use the same path.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.