Difference between revisions of "Quality policies and enforcement"
(→3. Compilation safeties) |
|||
(2 intermediate revisions by the same user not shown) | |||
Line 72: | Line 72: | ||
— <cite>Mark Minasi</cite> | — <cite>Mark Minasi</cite> | ||
− | = | + | =Coding awareness= |
The best way to code efficiently is to be inform right away inside our IDEs. Many plugins are available for ''Eclipse'' and ''IntelliJ''. | The best way to code efficiently is to be inform right away inside our IDEs. Many plugins are available for ''Eclipse'' and ''IntelliJ''. | ||
− | == | + | ==IntelliJ== |
You should manually install the following plugins: | You should manually install the following plugins: | ||
Line 103: | Line 103: | ||
− | == | + | ==Eclipse== |
Install the following plugins: | Install the following plugins: | ||
Line 113: | Line 113: | ||
* Infinitest | * Infinitest | ||
− | = | + | |
+ | |||
+ | =Support of each other= | ||
To help each other, please enable the '''javadoc generation''' and '''source code publication''' if your artefact is not confidential / something related to security. You do not want your colleague to harass you... You want them to challenge your code and design. :) | To help each other, please enable the '''javadoc generation''' and '''source code publication''' if your artefact is not confidential / something related to security. You do not want your colleague to harass you... You want them to challenge your code and design. :) | ||
Line 161: | Line 163: | ||
− | = | + | =Compilation safeties= |
'''> Do not forget to compile your code BEFORE commit and push''' | '''> Do not forget to compile your code BEFORE commit and push''' | ||
Line 168: | Line 170: | ||
− | == | + | ==Maven code quality principles== |
Maven relies on plugins to check the code quality. | Maven relies on plugins to check the code quality. | ||
Line 176: | Line 178: | ||
− | == | + | |
+ | ==BUILD configuration== | ||
These are the '''main plugins that always run'''. You should add them to your parent pom. | These are the '''main plugins that always run'''. You should add them to your parent pom. | ||
− | + | - Maven dependencies checks | |
+ | - OWASP vulnerabilities checks | ||
+ | |||
+ | Reports will be generated always, but only processed on request | ||
+ | |||
<syntaxhighlight lang="xml"> | <syntaxhighlight lang="xml"> | ||
Line 186: | Line 193: | ||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | ||
<!-- Plugin versions --> | <!-- Plugin versions --> | ||
− | |||
<dependency-plugin.version>3.1.1</dependency-plugin.version> | <dependency-plugin.version>3.1.1</dependency-plugin.version> | ||
− | |||
</properties> | </properties> | ||
Line 214: | Line 219: | ||
<ignoreNonCompile>true</ignoreNonCompile> | <ignoreNonCompile>true</ignoreNonCompile> | ||
<ignoredDependencies> | <ignoredDependencies> | ||
− | |||
<dependency>org.springframework</dependency> | <dependency>org.springframework</dependency> | ||
<dependency>org.springframework.boot</dependency> | <dependency>org.springframework.boot</dependency> | ||
</ignoredDependencies> | </ignoredDependencies> | ||
<ignoredUsedUndeclaredDependencies> | <ignoredUsedUndeclaredDependencies> | ||
− | + | <dependency>org.springframework</dependency> | |
− | <dependency>org.springframework | ||
− | |||
<dependency>org.springframework.boot</dependency> | <dependency>org.springframework.boot</dependency> | ||
<dependency>org.hibernate</dependency> | <dependency>org.hibernate</dependency> | ||
− | |||
</ignoredUsedUndeclaredDependencies> | </ignoredUsedUndeclaredDependencies> | ||
</configuration> | </configuration> | ||
Line 270: | Line 271: | ||
<groupId>org.apache.maven.plugins</groupId> | <groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-dependency-plugin</artifactId> | <artifactId>maven-dependency-plugin</artifactId> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</plugin> | </plugin> | ||
</plugins> | </plugins> | ||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
− | == | + | ==REPORTING configuration== |
Configuration below is '''optional'''. It is only useful if you plan to run <code>mvn site</code> | Configuration below is '''optional'''. It is only useful if you plan to run <code>mvn site</code> | ||
− | + | ♦ To generate the ''mvn site'' might be very long.. | |
Line 443: | Line 307: | ||
<report>plugins</report> | <report>plugins</report> | ||
<report>plugin-management</report> | <report>plugin-management</report> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
</reports> | </reports> | ||
</reportSet> | </reportSet> | ||
Line 608: | Line 394: | ||
</reporting> | </reporting> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | == | + | |
+ | ==Local build== | ||
Before commit, please run <code>mvn clean install</code> locally. It should always go smoothly. | Before commit, please run <code>mvn clean install</code> locally. It should always go smoothly. | ||
− | + | ♦ Do NOT skip tests locally. Tests must run on the local workstation | |
+ | |||
+ | |||
− | = | + | =Jenkins build= |
A jenkins build should always be successful. If not, '''you must IMMEDIATELY attend to it''': fix compilation errors, tests issues. | A jenkins build should always be successful. If not, '''you must IMMEDIATELY attend to it''': fix compilation errors, tests issues. | ||
Line 622: | Line 410: | ||
− | = | + | =Build enforcement= |
This is related to '''Jenkins build'''. | This is related to '''Jenkins build'''. | ||
− | + | ♦ Make sure to run <code>install</code> goal, not "<code>package</code>", because integration tests are only run at "<code>install</code>" phase. | |
− | + | ♦ Before you setup SonarQube, ensure that you are running Surefire & Failsafe always. If so, you should find "surefire-reports" / "failsafe-reports" folders + "jacoco.exec" files after compilation. | |
− | |||
Line 636: | Line 423: | ||
You must update your JenkinsFile to run the '''dependency-checks''' and '''sonarqube''' reporting tool. Here is an example: | You must update your JenkinsFile to run the '''dependency-checks''' and '''sonarqube''' reporting tool. Here is an example: | ||
− | |||
<syntaxhighlight lang="groovy"> | <syntaxhighlight lang="groovy"> |
Latest revision as of 08:13, 22 May 2019
This page does not talk about design but implementation and code delivery. This page describes how code quality is enforced.
Contents
Targets
The objectives are:
- Ensure the maintainability of the code
- Be sure that LuxTrust follow best practices and common design patterns. It will be easier to get inside the code by someone else later on
- Be sure that separation of concerns is well done. This will avoid cyclic dependencies, mix of data / business code at the same place, etc.
- Run OWASP dependencies check and be inform in case of security issues
- Enforce coding rules and formats (ex: tab /vs/ spaces, brackets, etc.)
- Control test coverage
- Enforce governance and internal policies
Means of success
To reach the targets, different means have been setup:
- Coding awareness == IDEs plugins
- Support of each other == generate project javadoc and publish source code of internal projects. If you do not trust the company members, how can you trust a 3rd party dependency ??
- Compilation safeties == maven plugins
- Build on push ; ALL TESTS MUST ALWAYS PASS == Jenkins
- Build enforcement / notifications == jenkins will run additional rules (ex: OWASP checks) and inform developers in case of issues
- SonarQube == static code analysis and quality control
- Code review / peer programming = to ensure code is really as good as it should be
Key points
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
— John F. Woods
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
— Martin Fowler
The best programs are written so that computing machines can perform them quickly and so that human beings can understand them clearly
— Donald E. Knuth
It’s OK to figure out murder mysteries, but you shouldn’t need to figure out code. You should be able to read it.
— Steve McConnell
Without requirements or design, programming is the art of adding bugs to an empty text file.
— Louis Srygley
Do not let "clichés" be right
If McDonalds were run like a software company, one out of every hundred Big Macs would give you food poisoning, and the response would be, "We’re sorry, here’s a coupon for two more."
— Mark Minasi
Coding awareness
The best way to code efficiently is to be inform right away inside our IDEs. Many plugins are available for Eclipse and IntelliJ.
IntelliJ
You should manually install the following plugins:
- Code quality (inspection)
- CodeMetrics : to know the cyclomatic complexity of each method. A must have
- Infinitest: to run unit tests automatically on method change. A must have
- SonarLint + SonarQube Community plugin : to see the alerts inside IntelliJ
- Code smell detector : to have alerts about bad / suspicious practices
- Checkstyle-IDEA : to have the Checkstyle rules
- Findbugs-IDEA : to have the FindBugs rules
- PMDPlugin : to have the PMD rules
- Utilities
- Maven helper : to view the maven dependencies graph
Some plugins must be enabled.
- Go to File > Settings > Other settings
- SonarLint General Settings
- Register sonarQube server. (i) to generate a Token go to "SonarQube" > login > My account > security
- SonarLint Project settings
- Select the new server
- Select the SonarQube project
- SonarQube
- Add Sonar server
- SonarLint General Settings
Eclipse
Install the following plugins:
- Checkstyle
- PMD
- Findbugs
- EmmaCodeCoverage (include in Eclipse since 2018)
- SonarQube
- Infinitest
Support of each other
To help each other, please enable the javadoc generation and source code publication if your artefact is not confidential / something related to security. You do not want your colleague to harass you... You want them to challenge your code and design. :)
In your maven POMs, please enable something like that (it can be done in the parent POM only):
<properties>
<maven.source.version>3.0.1</maven.source.version>
<javadoc.version>3.1.0</javadoc.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven.source.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${javadoc.version}</version>
<configuration>
<quiet>true</quiet>
<failOnWarnings>false</failOnWarnings>
<!-- add this to disable checking and ensure it will not failed on Java 8 -->
<doclint>none</doclint>
</configuration>
</plugin>
</plugins>
</build>
Compilation safeties
> Do not forget to compile your code BEFORE commit and push
Running Maven from the command line - without the black magic of the IDE - will give you a lot of warranty about your code.
Maven code quality principles
Maven relies on plugins to check the code quality.
- Some plugins always run: they are in the build / Plugins section
- Some plugins only run in particular cases: specific profiles or they are related to reports execution. These are in build / pluginsManagement section
- Some plugins are only executed on demand : they are in the reporting section
BUILD configuration
These are the main plugins that always run. You should add them to your parent pom. - Maven dependencies checks - OWASP vulnerabilities checks
Reports will be generated always, but only processed on request
<properties>
<!-- Set the reporting settings -->
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Plugin versions -->
<dependency-plugin.version>3.1.1</dependency-plugin.version>
</properties>
<build>
<!-- Global configuration. It will be used on request -->
<pluginManagement>
<plugins>
<!-- ==== packaging checks ==== -->
<!-- to check if some dependencies are unused or missing -->
<!-- Note that the dependency:analyze-only goal is used in preference to dependency:analyze since it doesn't force a further compilation of the project, but uses the compiled classes produced from the earlier compilation -->
<!-- usage: "mvn org.apache.maven.plugins:maven-dependency-plugin:analyze-only" -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${dependency-plugin.version}</version>
<executions>
<execution>
<id>analyze</id>
<goals>
<goal>analyze-only</goal>
</goals>
<configuration>
<failOnWarning>true</failOnWarning>
<outputXML>true</outputXML>
<ignoreNonCompile>true</ignoreNonCompile>
<ignoredDependencies>
<dependency>org.springframework</dependency>
<dependency>org.springframework.boot</dependency>
</ignoredDependencies>
<ignoredUsedUndeclaredDependencies>
<dependency>org.springframework</dependency>
<dependency>org.springframework.boot</dependency>
<dependency>org.hibernate</dependency>
</ignoredUsedUndeclaredDependencies>
</configuration>
</execution>
</executions>
</plugin>
<!-- ==== Security ==== -->
<!-- To check for vulnerabilities against the OWASP databases -->
<!-- usage: "mvn org.owasp:dependency-check-maven:check" -->
<!-- to aggregate all reports at once: "mvn org.owasp:dependency-check-maven:aggregate" -->
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>5.0.0-M3</version>
<configuration>
<failOnError>false</failOnError>
<formats>HTML,XML,JUNIT,JSON</formats>
</configuration>
</plugin>
<!-- ==== Reports ==== -->
<!-- To aggregate all reports into 1 website. This is mandatory to activate the "REPORTING" sections of the POM -->
<!-- This will offer a global view and navigation for (none exhaustive list): -->
<!-- dependency checks, OWASP checks, Jacoco reports (surefire unit tests + failsafe integration tests), etc. -->
<!-- This is only used when requested -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<locales>en</locales>
<!-- locales>en,fr</locales -->
</configuration>
</plugin>
</plugins>
</pluginManagement>
<!-- Plugins that will ALWAYS run -->
<plugins>
<plugin>
<!-- Always check that all dependencies are correctly set: no unused / no missing -->
<!-- Configuration of that plugin is externalized in the "pluginsManagement" section -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
</plugins>
REPORTING configuration
Configuration below is optional. It is only useful if you plan to run mvn site
♦ To generate the mvn site might be very long..
<reporting>
<plugins>
<!-- ==== Maven site === -->
<!-- Requirement for mvn site to display reports and aggregate content, since v3 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
<reportSets>
<!-- a) generate UNIT and INTEGRATION tests reports by modules -->
<reportSet>
<id>global-info</id>
<inherited>true</inherited>
<reports>
<!-- full list available at: https://maven.apache.org/plugins/maven-project-info-reports-plugin/plugin-info.html -->
<report>summary</report>
<report>modules</report>
<!-- List of dependencies and plugins -->
<report>dependencies</report>
<report>dependency-management</report>
<report>plugins</report>
<report>plugin-management</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!-- ===== Javadoc ===== -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${javadoc.version}</version>
<configuration>
<quiet>true</quiet>
<failOnError>false</failOnError>
</configuration>
<reportSets>
<!-- Generate modules reporting -->
<reportSet>
<id>javadoc</id>
<inherited>true</inherited>
<reports>
<report>javadoc-no-fork</report>
</reports>
</reportSet>
<!-- Aggregate javadoc -->
<reportSet>
<id>javadoc-aggregate</id>
<inherited>false</inherited>
<reports>
<report>aggregate-no-fork</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!-- ===== Checkstyle static analysis report ===== -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<!-- There are 2 predefined rulesets included in Maven Checkstyle Plugin:
* sun_checks.xml: Sun Checks
* google_checks.xml: Google Checks
-->
<configLocation>google_checks.xml</configLocation>
<linkXRef>false</linkXRef>
</configuration>
<reportSets>
<!-- Generate modules reporting -->
<reportSet>
<id>checkstyle</id>
<inherited>true</inherited>
<reports>
<report>checkstyle</report>
</reports>
</reportSet>
<!-- Aggregate all reports at parent level -->
<reportSet>
<id>checkstyle-aggregate</id>
<inherited>false</inherited>
<reports>
<report>checkstyle-aggregate</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!-- ===== PMD static analysis report ===== -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.12.0</version>
<configuration>
<linkXRef>false</linkXRef>
</configuration>
<reportSets>
<!-- Generate reports -->
<reportSet>
<reports>
<report>pmd</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
Local build
Before commit, please run mvn clean install
locally. It should always go smoothly.
♦ Do NOT skip tests locally. Tests must run on the local workstation
Jenkins build
A jenkins build should always be successful. If not, you must IMMEDIATELY attend to it: fix compilation errors, tests issues.
Build enforcement
This is related to Jenkins build.
♦ Make sure to run install
goal, not "package
", because integration tests are only run at "install
" phase.
♦ Before you setup SonarQube, ensure that you are running Surefire & Failsafe always. If so, you should find "surefire-reports" / "failsafe-reports" folders + "jacoco.exec" files after compilation.
You must update your JenkinsFile to run the dependency-checks and sonarqube reporting tool. Here is an example:
stage('Build') {
when {
// condition
}
steps {
withMaven(
maven: 'Maven 3.5.2',
mavenLocalRepo: '.repository'
) {
// Build
echo "Build"
sh "mvn clean install"
// MVN dependencies check
echo "MVN dependencies checks [unused/missing/outdated/etc]"
sh "mvn org.apache.maven.plugins:maven-dependency-plugin:analyze-report"
// Publish coverage reports
jacoco(
changeBuildStatus: false,
execPattern: '**/*.exec',
sourcePattern: 'src/main/java',
classPattern: 'target/classes',
exclusionPattern: '**/*Exception*,**/*Configuration*,**/ApiApplication*'
)
// OWASP dependencies checks
echo "OWASP dependencies checks"
sh "mvn org.owasp:dependency-check-maven:check"
// sh "mvn org.owasp:dependency-check-maven:aggregate"
dependencyCheckPublisher failedTotalHigh: '0', unstableTotalHigh: '1', failedTotalNormal: '2', unstableTotalNormal: '5'
// SonarQube
echo "Checking code quality"
withSonarQubeEnv('sonarqube') {
// Mind the version over there - it must match Jenkins
sh "mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.6.0.1398:sonar -Dsonar.projectName=\"PROJECT ($BRANCH_NAME)\" -Dsonar.projectKey=PROJECT:$BRANCH_NAME"
}
}
}
}
6. SonarQube
By default there will be 1 sonarqube' entry for every Jenkins artifactId that is build (parent name).