Maven Dependency project on Google Cloud Build with SonarScanner - maven

I will try to keep the description brief. We have a couple of projects. Some of them are full blown Spring Boot apps, some of them are Maven Dependency projects (used in those Spring Boot apps).
I have set up a Jenkins server for automating pipelines. Jenkins calls Google Cloud Build to build projects/docker images and cache dependencies. It also calls SonarQube in a step. This all works fine for the Spring Boot apps, but the SonarQube step fails for the dependency projects. The error is Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar (default-cli) on project projectname: Not inside a Git work tree: / -> [Help 1].
The Dockerfile for the project:
FROM maven:3.5-jdk-8-alpine
# Copy local code to the container image.
COPY pom.xml settings.xml ./
RUN mvn -s settings.xml dependency:go-offline
COPY src ./src
# Build a release artifact.
RUN mvn verify -DskipTests -s settings.xml
The cloudbuild.yaml:
substitutions:
_IMAGE_NAME: "projectname"
steps:
- name: "docker"
entrypoint: "sh"
args:
- "-c"
- |-
docker pull gcr.io/gcp-project/${_IMAGE_NAME}:$_TAG
docker pull gcr.io/gcp-project/${_IMAGE_NAME}:latest || true
- name: "docker"
args:
- "build"
- "-t"
- "gcr.io/gcp-project/${_IMAGE_NAME}"
- "-t"
- "gcr.io/gcp-project/${_IMAGE_NAME}:$_TAG"
- "--cache-from"
- "gcr.io/gcp-project/${_IMAGE_NAME}:latest"
- "--cache-from"
- "gcr.io/gcp-project/${_IMAGE_NAME}:$_TAG"
- "."
- name: "gcr.io/gcp-project/${_IMAGE_NAME}"
entrypoint: "bash"
args:
- "-ce"
- |-
mvn -f /pom.xml -s ./settings.xml sonar:sonar -Dsonar.host.url=https://sonar.server.com -Dsonar.login=${_SONAR_KEY}
- name: "gcr.io/gcp-project/${_IMAGE_NAME}"
args:
- "mvn"
- "deploy"
- "-s"
- "/settings.xml"
images: ["gcr.io/gcp-project/${_IMAGE_NAME}"]
There are two very confusing things. If i run the maven command locally, the analysis completes successfully. Also, if i run the local Google Cloud Build tool (cloud-build-local) it also passes.
I have verified that the .git folder is not uploaded. It is neither with the Spring Boot apps.
I copied the settings.xml from the Jenkins server locally and used that one. Neither the Spring Boot apps or the dependencies define a sonar-project.properties.
Is there anyone who can shed some light on this?
Thanks in advance!
EDIT
I created 2 repositories that are able to replicate this problem:
Non-working: https://github.com/claystation/mvnsonarapp
Working: https://github.com/claystation/mvnsonarappworking
I think the main difference is the dependency project not having #SpringBootApplication?

Ok, so i finally figured it out how to solve this, by doing the MCVE.. Unfortunately not WHY the problem exists.
The main difference between the projects was the #SpringBootApplication annotation. I thought this might have something to do with having the spring-boot-starter-parent parent defined.
I removed the parent part and now my project is passing in Sonar. If there is ever someone who can explain WHY Sonar gives this error with the parent defined but no #SpringBootApplication annotation, that would be very helpful.
Thanks!

Related

Why does gradle build locations differently locally and via gitlab pipelines?

Basic Spring Boot app with Gradle.
If I build locally with Gradle using
./gradlew clean build
my jar is in
build/
But when using GitLab's pipelines with the following config
gradle-build:
image: gradle:alpine
stage: build
script:
- ./gradlew clean build
artifacts:
paths:
- build/libs/*.jar
The jar is in
build/libs
The "artifacts -> paths" config is just to share the jar with the next step of the pipeline, which is building the docker container.
So why the difference between the 2 ?
I like to have consistency and have the same thing locally as on the build server.
Thanks.

Maven build in github continuous integration action

I am using Github actions to set up a continuous integration workflow for a Maven app. The Maven app depends on some external dependencies as well as a couple other repositories that we built. In my Github action's .yaml file, I've included the line "mvn install". When I make a commit, the action begins to run the .yaml file as expected. The build mostly works, and can find external maven dependencies from maven central. However, the build cannot find the two other private repositories. These repositories are saved on the same github account as the repo. for this app.
Downloading from central: https://repo.maven.apache.org/maven2/com/<repo>/1.3/<repoName>-1.3.pom
[WARNING] The POM for com.<repo>/<reponame>.core:jar:1.3 is missing, no dependency information available
Here is my github/workflow action's yaml file...
name: Build1
on:
push:
branches:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v1
- name: Run a one-line script
run: echo Hello, world!
- name: Run a multi-line script
run: |
echo Add other actions to build,
echo test, and deploy your project.
- name: Build
run: mvn install

Docker Spring Boot project local Snapshot Dependency

I am learning docker to work with my spring boot application. I am not able to load Snapshot versions of dependent project.
I have two projects, Project A and Project B.
this is my docker-compose file
version: '2.1'
services:
projectA:
build:
context: ./projectA
dockerfile: Dockerfile
restart: always
working_dir: /app
command: mvn clean install
projectB:
build:
context: ./projectB
dockerfile: Dockerfile
restart: always
working_dir: /app
command: mvn clean spring-boot:run
This generates the Snapshot Jar projectA-1.1.0-SNAPSHOT.jar
I want to use this jar in projectB ( Spring Boot Application)
How can I point yo This local jar in POM.xml
My POM Should have
<dependency>
<groupId>com.project.test</groupId>
<artifactId>projectA</artifactId>
<version>1.1.0-SNAPSHOT</version>
</dependency>
I am getting errors while loading projectB due to changes in SNAPSHOT version.
Thanks,
this is the output when I do docker-compose up --build
[ERROR] COMPILATION ERROR :
[INFO] ----------------------------
[ERROR].../com/project/test/api/assembler/UserMapper.java:
[57,54] cannot find symbol
symbol: method getLastSessionTimestamp()
location: variable user of type com.project.test.domain.User
lastSessionTimestamp is added in local SNAPSHOT Jar.
The reason why your example can't work is that you have a misconception of what docker (compose) is and how it works. It is not a package manager for your java libraries but a tool to wrap entire applications together.
So in detail what you configured is the following: projectA builds a docker container using your Dockerfile builds projectA java libraries and finally installs the packaged jarfile into the docker container local filesystems maven folders. Additionally in parallel you are trying to start projectB. That means you have two problems:
the running containers don't know about each other as they are not sharing anything, but even if you would solve this problem, e.g. by sharing a volume amongst them you still have problem
compose doesn't imply an order and executes multiple containers in parallel. So you might run into situations where it might work and on the next run will not work again as B is executed before A is done.
To solve this you have a couple of options of which I would suggest to do the following:
- Build A and B outside of containers on your machine using a multi module pom file that orchestrates the build and only add the final jar to a docker image that you can ship. If that works you can also execute the build in a container.
But to simply try out that both your builds work you can create a volume and mount it in both containers into the maven folder which is /root/.m2 assuming you didn't changed the default user.
But I strongly suggest you also have a read on how docker treats multistage builds and how it handles volumes here:
Docker volumes
Multi-Stage Builds

Gitlab appengine:deploy missing JAR on Gitlab only

I have setup a multi module spring boot application including Google appengine integration. Locally everything works fine.
If I do a clean checkout of my GIT repo and after that execute
mvn clean install
mvn appengine:deploy
The app gets properly deployed to Google appengine
If I try to do the same on gitlab using the following deploy pipeline
deploy-prod:
stage: deploy
image: $CI_REGISTRY_IMAGE/build
when: manual
environment: prod
script:
- 'mvn clean install'
- 'mvn appengine:deploy'
I get an error saying:
Failed to execute goal on project XXX: Could not resolve dependencies
for project YYY:XXX:war:0.0.1-SNAPSHOT: Could not find artifact
YYY:XXX:jar:0.0.1-SNAPSHOT
Do you have any idea what is wrong/different here? Never had such problems on Gitlab? And I have no idea what is different to the case when I do a clean checkout locally and execute the same commands there?
Thanks for your help.
I assume, you are checking it at your local machine. But have you checked it with $CI_REGISTRY_IMAGE/build manually? I think there is an issue with the docker image itself.

GitLab CI How to trigger pipeline for submodules in maven multi-module project

I have a multi-module Maven project:
root
SubmoduleA
src
pom.xml
SubmoduleB
src
pom.xml
pom.xml
.gitlab-ci.yml
Is there any way I can trigger a CI pipeline only on SubmoduleA when somebody checks in code that only affects SubmoduleA?
For example, someone makes a change in SubmoduleA. Once they commit and push, I want to automatically run build->test->deploy only on SubmoduleA since there were no changes to SubmoduleB.
Is there a way to specify triggers and jobs for specific sub-modules or sub-projects within a repo?
I believe you need to create a gitlab project for that sub-module and that sub-module needs its own .gitlab-ci.yml. At that point it will be buildable inside the gitlab-ci-runner itself.
I am not an expert in Maven (or Java) but I imagine that in larger projects your submodules could become separate binary built libraries stored in your own in-house repositories. You both produce and consume jars in your build, and you serve them using Maven itself. Maven can then download for you using its built in dependency resolution and package fetching features, and that perhaps you would be better off in a large Java project build scenario with that, than with git submodules.
I do this right now in the .Net world with a custom nuget feed and the results are similar to what you're doing, in that builds happen and the build server's resources do not get wasted by source-including and recompiling those modules a second time.
Gitlab can trigger job on catalog change: https://docs.gitlab.com/ee/ci/yaml/#onlychanges
For this solution:
you should enable gitlab cache for maven repository to keep previous build modules.
then you can define job for path change
stages:
- modules
- build
moduleB:
stage: modules
script:
- mvn $MAVEN_OPTS -pl projectB clean install --also-make $MAVEN_CLI_OPTS
only:
changes:
- projectB/**
master_job:
stage: build
dependencies:
- projectB
script:
- >
mvn $MAVEN_OPTS -pl projectA clean install $MAVEN_CLI_OPTS
Gitlab has a few options to build your CI/CD:
Basic
DAG
Child/Parent
You can mix them. They are not mutual exclusive.
You are interested in Child/Parent
stages:
- triggers
trigger_a:
stage: triggers
trigger:
include: a/.gitlab-ci.yml
rules:
- changes:
- a/*
trigger_b:
stage: triggers
trigger:
include: b/.gitlab-ci.yml
rules:
- changes:
- b/*
Then you have to include the pipelines for a and b projects. You can find more in their documentation

Resources