From c7dd21af0f224d144b13a87c0ed183cf529c5234 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Fri, 31 Jan 2025 11:21:38 +0100 Subject: [PATCH 01/18] Create task that opens test results --- build.gradle | 27 +++++++++++++++++++++++++++ settings.gradle | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 17c3763e2..69473b570 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,11 @@ plugins { id 'org.cyclonedx.bom' version '1.10.0' id 'io.spring.javaformat' version '0.0.43' id "io.spring.nohttp" version "0.0.11" + id("pl.allegro.tech.build.axion-release") version "1.18.7" } +version = scmVersion.version + apply plugin: 'java' apply plugin: 'checkstyle' apply plugin: 'io.spring.javaformat' @@ -80,6 +83,30 @@ tasks.named("formatMain").configure { dependsOn("checkstyleNohttp") } tasks.named("formatTest").configure { dependsOn("checkstyleTest") } tasks.named("formatTest").configure { dependsOn("checkstyleNohttp") } + +task openTestResults(dependsOn: ['build', 'test']) { + doLast { + def testResultsFile = file('build/reports/tests/test/index.html') + + if (testResultsFile.exists()) { + println "Opening test results in the browser..." + // Open the test results file in the default browser (cross-platform) + if (System.getProperty('os.name').toLowerCase().contains('win')) { + // On Windows, use "start" + "cmd /c start ${testResultsFile}".execute() + } else if (System.getProperty('os.name').toLowerCase().contains('mac')) { + // On macOS, use "open" + "open ${testResultsFile}".execute() + } else { + // On Linux, use "xdg-open" + "xdg-open ${testResultsFile}".execute() + } + } else { + throw new GradleException("Test results file not found: ${testResultsFile}") + } + } +} + checkstyleAot.enabled = false checkstyleAotTest.enabled = false diff --git a/settings.gradle b/settings.gradle index e60ee14fa..c9cf4f1fc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -rootProject.name = 'spring-petclinic' +rootProject.name = 'spring-application' From 22eac78c283363c80ec3ee34f5c860df601a5f76 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Fri, 31 Jan 2025 18:28:10 +0100 Subject: [PATCH 02/18] Add task for deploying artifacts to Nexus --- .gitignore | 2 ++ build.gradle | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d2767ad28..b13718629 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,5 @@ out/ _site/ *.css !petclinic.css + +gradle.properties diff --git a/build.gradle b/build.gradle index 69473b570..8e3548658 100644 --- a/build.gradle +++ b/build.gradle @@ -7,6 +7,7 @@ plugins { id 'io.spring.javaformat' version '0.0.43' id "io.spring.nohttp" version "0.0.11" id("pl.allegro.tech.build.axion-release") version "1.18.7" + id('maven-publish') } version = scmVersion.version @@ -20,14 +21,42 @@ gradle.startParameter.excludedTaskNames += [ "checkFormatAot", "checkFormatAotTe group = 'org.springframework.samples' version = '3.4.0' +def nexusUsername = project.hasProperty('nexusUsername') ? project.nexusUsername : System.getenv('NEXUS_USERNAME') +def nexusPassword = project.hasProperty('nexusPassword') ? project.nexusPassword : System.getenv('NEXUS_PASSWORD') java { sourceCompatibility = JavaVersion.VERSION_17 } repositories { - mavenCentral() + maven { + url 'http://localhost:8081/repository/maven-central/' + allowInsecureProtocol = true + } + mavenCentral() } +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + artifact file("build/libs/spring-application-${version}.jar") + } + } + + repositories { + maven { + name = "maven-releases" + url 'http://localhost:8081/repository/maven-releases/' + allowInsecureProtocol = true + credentials { + username nexusUsername + password nexusPassword + } + } + } +} + + ext.checkstyleVersion = "10.20.1" ext.springJavaformatCheckstyleVersion = "0.0.43" ext.webjarsLocatorLiteVersion = "1.0.1" @@ -61,6 +90,7 @@ dependencies { testImplementation 'org.testcontainers:mysql' checkstyle "io.spring.javaformat:spring-javaformat-checkstyle:${springJavaformatCheckstyleVersion}" checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}" + testImplementation 'junit:junit:4.13' } tasks.named('test') { @@ -107,6 +137,15 @@ task openTestResults(dependsOn: ['build', 'test']) { } } +task testProxy { + doLast { + def url = new URL('http://localhost:8081/repository/maven-central') + def connection = url.openConnection() + connection.connect() + println "Proxy connection successful to Maven Central!" + } +} + checkstyleAot.enabled = false checkstyleAotTest.enabled = false From a8b3245c21aebdbfa6fa345b9ca57cfd0b31309f Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Tue, 11 Feb 2025 17:47:13 +0100 Subject: [PATCH 03/18] Remove dependence on Nexus in build.gradle file --- build.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build.gradle b/build.gradle index 8e3548658..17d38fa90 100644 --- a/build.gradle +++ b/build.gradle @@ -28,10 +28,6 @@ java { } repositories { - maven { - url 'http://localhost:8081/repository/maven-central/' - allowInsecureProtocol = true - } mavenCentral() } From c9022c2789a6cc6a308119863a553b226c725856 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Tue, 11 Feb 2025 17:50:26 +0100 Subject: [PATCH 04/18] Add docker-compose file that run application with database --- docker-compose.yml | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 47579bbaf..84237659a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,19 @@ services: - mysql: - image: mysql:9.1 + app: + image: spring-app:latest ports: - - "3306:3306" - environment: - - MYSQL_ROOT_PASSWORD= - - MYSQL_ALLOW_EMPTY_PASSWORD=true - - MYSQL_USER=petclinic - - MYSQL_PASSWORD=petclinic - - MYSQL_DATABASE=petclinic - volumes: - - "./conf.d:/etc/mysql/conf.d:ro" + - "8080:8080" + postgres: image: postgres:17.0 ports: - "5432:5432" environment: - - POSTGRES_PASSWORD=petclinic - - POSTGRES_USER=petclinic - - POSTGRES_DB=petclinic + POSTGRES_PASSWORD: petclinic + POSTGRES_USER: petclinic + POSTGRES_DB: petclinic + volumes: + - pgdata:/var/lib/postgresql/data + +volumes: + pgdata: From 324c795b1fbd5b5ece9d48bbe9a20477d61915f3 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Tue, 11 Feb 2025 17:59:38 +0100 Subject: [PATCH 05/18] Add Dockerfile --- Dockerfile | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..76f27a44f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM gradle:8.5-jdk17 AS build + +WORKDIR /app + +COPY . /app + +RUN gradle clean build + +FROM eclipse-temurin:17-jre + +WORKDIR /app + +COPY --from=build /app/build/libs/*.jar app.jar + +EXPOSE 8080 + +ENTRYPOINT ["java", "-jar", "app.jar"] From ff2310679430993a64da486e280efd2d79ae1979 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Wed, 12 Feb 2025 10:00:29 +0100 Subject: [PATCH 06/18] Add Jenkinsfile --- Jenkinsfile | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000..0b6adbaf5 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,54 @@ +pipeline { + agent any + + environment { + // Define environment variables + DOCKER_REGISTRY = "docker.io" + DOCKER_IMAGE = "mmarcetic/main" + DOCKER_CREDENTIALS = "Docker_hub" + } + + stages { + stage('Checkout') { + steps { + // Checkout the code from the repository + checkout scm + } + } + + stage('Build Docker Image') { + steps { + script { + // Build the Docker image + sh 'docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest .' + } + } + } + + stage('Push Docker Image') { + steps { + script { + //Login to the Docker repository + docker.withRegistry('https://${DOCKER_REGISTRY}', "${DOCKER_CREDENTIALS}") { + // Push the Docker image to the registry + sh 'docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest' + } + } + } + } + } + + post { + always { + // Clean up Docker images after the job is done + sh 'docker rmi ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest || true' + } + success { + echo 'Docker image built and pushed successfully.' + } + failure { + echo 'Pipeline failed!' + } + } +} + From 9f8eb38d0c18961b0f6f58efb51fba088458e58e Mon Sep 17 00:00:00 2001 From: MMarceticGrid Date: Thu, 6 Mar 2025 16:04:20 +0100 Subject: [PATCH 07/18] Update Jenkinsfile --- Jenkinsfile | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0b6adbaf5..704efab41 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,6 @@ pipeline { // Define environment variables DOCKER_REGISTRY = "docker.io" DOCKER_IMAGE = "mmarcetic/main" - DOCKER_CREDENTIALS = "Docker_hub" } stages { @@ -20,7 +19,8 @@ pipeline { steps { script { // Build the Docker image - sh 'docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest .' + def gitCommit = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() + sh "docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${gitCommit} ." } } } @@ -28,10 +28,10 @@ pipeline { stage('Push Docker Image') { steps { script { - //Login to the Docker repository - docker.withRegistry('https://${DOCKER_REGISTRY}', "${DOCKER_CREDENTIALS}") { - // Push the Docker image to the registry - sh 'docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest' + def gitCommit = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() + withCredentials([usernamePassword(credentialsId: "docker-login", usernameVariable: "DOCKER_USER", passwordVariable: "DOCKER_PASSWORD")]) { + sh "docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}" + sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${gitCommit}" } } } @@ -39,10 +39,6 @@ pipeline { } post { - always { - // Clean up Docker images after the job is done - sh 'docker rmi ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest || true' - } success { echo 'Docker image built and pushed successfully.' } From f32d17fd4202984481bf80f4ccbb397ec17e5610 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Fri, 31 Jan 2025 11:21:38 +0100 Subject: [PATCH 08/18] Create task that opens test results Signed-off-by: Mihailo --- build.gradle | 27 +++++++++++++++++++++++++++ settings.gradle | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 17c3763e2..69473b570 100644 --- a/build.gradle +++ b/build.gradle @@ -6,8 +6,11 @@ plugins { id 'org.cyclonedx.bom' version '1.10.0' id 'io.spring.javaformat' version '0.0.43' id "io.spring.nohttp" version "0.0.11" + id("pl.allegro.tech.build.axion-release") version "1.18.7" } +version = scmVersion.version + apply plugin: 'java' apply plugin: 'checkstyle' apply plugin: 'io.spring.javaformat' @@ -80,6 +83,30 @@ tasks.named("formatMain").configure { dependsOn("checkstyleNohttp") } tasks.named("formatTest").configure { dependsOn("checkstyleTest") } tasks.named("formatTest").configure { dependsOn("checkstyleNohttp") } + +task openTestResults(dependsOn: ['build', 'test']) { + doLast { + def testResultsFile = file('build/reports/tests/test/index.html') + + if (testResultsFile.exists()) { + println "Opening test results in the browser..." + // Open the test results file in the default browser (cross-platform) + if (System.getProperty('os.name').toLowerCase().contains('win')) { + // On Windows, use "start" + "cmd /c start ${testResultsFile}".execute() + } else if (System.getProperty('os.name').toLowerCase().contains('mac')) { + // On macOS, use "open" + "open ${testResultsFile}".execute() + } else { + // On Linux, use "xdg-open" + "xdg-open ${testResultsFile}".execute() + } + } else { + throw new GradleException("Test results file not found: ${testResultsFile}") + } + } +} + checkstyleAot.enabled = false checkstyleAotTest.enabled = false diff --git a/settings.gradle b/settings.gradle index e60ee14fa..c9cf4f1fc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -rootProject.name = 'spring-petclinic' +rootProject.name = 'spring-application' From 89511d3b42b05d04dda77f44514f21b7a3ee9379 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Fri, 31 Jan 2025 18:28:10 +0100 Subject: [PATCH 09/18] Add task for deploying artifacts to Nexus Signed-off-by: Mihailo --- .gitignore | 2 ++ build.gradle | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d2767ad28..b13718629 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,5 @@ out/ _site/ *.css !petclinic.css + +gradle.properties diff --git a/build.gradle b/build.gradle index 69473b570..8e3548658 100644 --- a/build.gradle +++ b/build.gradle @@ -7,6 +7,7 @@ plugins { id 'io.spring.javaformat' version '0.0.43' id "io.spring.nohttp" version "0.0.11" id("pl.allegro.tech.build.axion-release") version "1.18.7" + id('maven-publish') } version = scmVersion.version @@ -20,14 +21,42 @@ gradle.startParameter.excludedTaskNames += [ "checkFormatAot", "checkFormatAotTe group = 'org.springframework.samples' version = '3.4.0' +def nexusUsername = project.hasProperty('nexusUsername') ? project.nexusUsername : System.getenv('NEXUS_USERNAME') +def nexusPassword = project.hasProperty('nexusPassword') ? project.nexusPassword : System.getenv('NEXUS_PASSWORD') java { sourceCompatibility = JavaVersion.VERSION_17 } repositories { - mavenCentral() + maven { + url 'http://localhost:8081/repository/maven-central/' + allowInsecureProtocol = true + } + mavenCentral() } +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + artifact file("build/libs/spring-application-${version}.jar") + } + } + + repositories { + maven { + name = "maven-releases" + url 'http://localhost:8081/repository/maven-releases/' + allowInsecureProtocol = true + credentials { + username nexusUsername + password nexusPassword + } + } + } +} + + ext.checkstyleVersion = "10.20.1" ext.springJavaformatCheckstyleVersion = "0.0.43" ext.webjarsLocatorLiteVersion = "1.0.1" @@ -61,6 +90,7 @@ dependencies { testImplementation 'org.testcontainers:mysql' checkstyle "io.spring.javaformat:spring-javaformat-checkstyle:${springJavaformatCheckstyleVersion}" checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}" + testImplementation 'junit:junit:4.13' } tasks.named('test') { @@ -107,6 +137,15 @@ task openTestResults(dependsOn: ['build', 'test']) { } } +task testProxy { + doLast { + def url = new URL('http://localhost:8081/repository/maven-central') + def connection = url.openConnection() + connection.connect() + println "Proxy connection successful to Maven Central!" + } +} + checkstyleAot.enabled = false checkstyleAotTest.enabled = false From ceb2bc79dba3bb7a975a353a375ac7c9ca7f6732 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Tue, 11 Feb 2025 17:47:13 +0100 Subject: [PATCH 10/18] Remove dependence on Nexus in build.gradle file Signed-off-by: Mihailo --- build.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build.gradle b/build.gradle index 8e3548658..17d38fa90 100644 --- a/build.gradle +++ b/build.gradle @@ -28,10 +28,6 @@ java { } repositories { - maven { - url 'http://localhost:8081/repository/maven-central/' - allowInsecureProtocol = true - } mavenCentral() } From a2848f9132d44788529b6fc21bd949a119ac2b14 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Tue, 11 Feb 2025 17:50:26 +0100 Subject: [PATCH 11/18] Add docker-compose file that run application with database Signed-off-by: Mihailo --- docker-compose.yml | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 47579bbaf..84237659a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,19 @@ services: - mysql: - image: mysql:9.1 + app: + image: spring-app:latest ports: - - "3306:3306" - environment: - - MYSQL_ROOT_PASSWORD= - - MYSQL_ALLOW_EMPTY_PASSWORD=true - - MYSQL_USER=petclinic - - MYSQL_PASSWORD=petclinic - - MYSQL_DATABASE=petclinic - volumes: - - "./conf.d:/etc/mysql/conf.d:ro" + - "8080:8080" + postgres: image: postgres:17.0 ports: - "5432:5432" environment: - - POSTGRES_PASSWORD=petclinic - - POSTGRES_USER=petclinic - - POSTGRES_DB=petclinic + POSTGRES_PASSWORD: petclinic + POSTGRES_USER: petclinic + POSTGRES_DB: petclinic + volumes: + - pgdata:/var/lib/postgresql/data + +volumes: + pgdata: From ba9fd2a991e098a6efa2aa9c99a0a6db2c5c6132 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Tue, 11 Feb 2025 17:59:38 +0100 Subject: [PATCH 12/18] Add Dockerfile Signed-off-by: Mihailo --- Dockerfile | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..76f27a44f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM gradle:8.5-jdk17 AS build + +WORKDIR /app + +COPY . /app + +RUN gradle clean build + +FROM eclipse-temurin:17-jre + +WORKDIR /app + +COPY --from=build /app/build/libs/*.jar app.jar + +EXPOSE 8080 + +ENTRYPOINT ["java", "-jar", "app.jar"] From 684e04e70372646bff15bbc6f08c01b258cba658 Mon Sep 17 00:00:00 2001 From: Mihailo Marcetic Date: Wed, 12 Feb 2025 10:00:29 +0100 Subject: [PATCH 13/18] Add Jenkinsfile Signed-off-by: Mihailo --- Jenkinsfile | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000..0b6adbaf5 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,54 @@ +pipeline { + agent any + + environment { + // Define environment variables + DOCKER_REGISTRY = "docker.io" + DOCKER_IMAGE = "mmarcetic/main" + DOCKER_CREDENTIALS = "Docker_hub" + } + + stages { + stage('Checkout') { + steps { + // Checkout the code from the repository + checkout scm + } + } + + stage('Build Docker Image') { + steps { + script { + // Build the Docker image + sh 'docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest .' + } + } + } + + stage('Push Docker Image') { + steps { + script { + //Login to the Docker repository + docker.withRegistry('https://${DOCKER_REGISTRY}', "${DOCKER_CREDENTIALS}") { + // Push the Docker image to the registry + sh 'docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest' + } + } + } + } + } + + post { + always { + // Clean up Docker images after the job is done + sh 'docker rmi ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest || true' + } + success { + echo 'Docker image built and pushed successfully.' + } + failure { + echo 'Pipeline failed!' + } + } +} + From 0dce1f7d2b09f7e87d9f27e28e6315f1abbd0377 Mon Sep 17 00:00:00 2001 From: MMarceticGrid Date: Thu, 6 Mar 2025 16:04:20 +0100 Subject: [PATCH 14/18] Update Jenkinsfile Signed-off-by: Mihailo --- Jenkinsfile | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0b6adbaf5..704efab41 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,6 @@ pipeline { // Define environment variables DOCKER_REGISTRY = "docker.io" DOCKER_IMAGE = "mmarcetic/main" - DOCKER_CREDENTIALS = "Docker_hub" } stages { @@ -20,7 +19,8 @@ pipeline { steps { script { // Build the Docker image - sh 'docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest .' + def gitCommit = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() + sh "docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${gitCommit} ." } } } @@ -28,10 +28,10 @@ pipeline { stage('Push Docker Image') { steps { script { - //Login to the Docker repository - docker.withRegistry('https://${DOCKER_REGISTRY}', "${DOCKER_CREDENTIALS}") { - // Push the Docker image to the registry - sh 'docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest' + def gitCommit = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() + withCredentials([usernamePassword(credentialsId: "docker-login", usernameVariable: "DOCKER_USER", passwordVariable: "DOCKER_PASSWORD")]) { + sh "docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}" + sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${gitCommit}" } } } @@ -39,10 +39,6 @@ pipeline { } post { - always { - // Clean up Docker images after the job is done - sh 'docker rmi ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:latest || true' - } success { echo 'Docker image built and pushed successfully.' } From 61a75b5570c77d1677fa056012ded8747dc90fab Mon Sep 17 00:00:00 2001 From: Mihailo Date: Fri, 7 Mar 2025 10:13:26 +0100 Subject: [PATCH 15/18] Add deployment and service for kind cluster Signed-off-by: Mihailo --- deployment.yaml | 22 ++++++++++++++++++++++ service.yaml | 15 +++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 deployment.yaml create mode 100644 service.yaml diff --git a/deployment.yaml b/deployment.yaml new file mode 100644 index 000000000..f9c23ef7b --- /dev/null +++ b/deployment.yaml @@ -0,0 +1,22 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: spring-boot-app + namespace: petclinic +spec: + replicas: 2 + selector: + matchLabels: + app: spring-boot-app + template: + metadata: + labels: + app: spring-boot-app + spec: + containers: + - name: spring-boot-app + image: docker.io/mmarcetic/main:2.0 + imagePullPolicy: Always + ports: + - containerPort: 8080 + diff --git a/service.yaml b/service.yaml new file mode 100644 index 000000000..e0547ec6a --- /dev/null +++ b/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: spring-boot-app-service + namespace: petclinic +spec: + selector: + app: spring-boot-app + ports: + - protocol: TCP + port: 80 + targetPort: 8080 + nodePort: 30950 + type: NodePort + From 29b73475db46024cfa254a5848b73e54777586bd Mon Sep 17 00:00:00 2001 From: Mihailo Date: Fri, 7 Mar 2025 12:08:48 +0100 Subject: [PATCH 16/18] Add more stages to Jenkinsfile --- Jenkinsfile | 86 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 704efab41..68a97fd90 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -4,7 +4,9 @@ pipeline { environment { // Define environment variables DOCKER_REGISTRY = "docker.io" - DOCKER_IMAGE = "mmarcetic/main" + DOCKER_IMAGE_MAIN = 'mmarcetic/main' + DOCKER_IMAGE_MR = 'mmarcetic/mr' + GIT_COMMIT = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() } stages { @@ -15,23 +17,91 @@ pipeline { } } - stage('Build Docker Image') { + stage('Set Docker Image') { steps { script { - // Build the Docker image - def gitCommit = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() - sh "docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${gitCommit} ." + // Set Docker image based on the branch name + if (env.BRANCH_NAME == 'main') { + env.DOCKER_IMAGE = DOCKER_IMAGE_MAIN + } else { + env.DOCKER_IMAGE = DOCKER_IMAGE_MR + } + + echo "Using Docker image: ${env.DOCKER_IMAGE}" } } } - stage('Push Docker Image') { + stage('Checkstyle Report') { + when { + changeRequest() + } + steps { + script { + // Checkstyle with Gradle + sh './gradlew checkstyleMain' + archiveArtifacts artifacts: 'build/reports/checkstyle/checkstyle.xml' + } + } + } + + stage('Test') { + when { + changeRequest() + } + steps { + // Test using Gradle + sh './gradlew test' + } + } + + stage('Build Without Tests') { + when { + changeRequest() + } + steps { + script { + // Build without tests using Gradle + sh './gradlew build -x test' + } + } + } + + stage('Build Docker Image') { + when { + changeRequest() + } + steps { + script { + // Build the Docker image + sh "docker build -t ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${GIT_COMMIT} ." + } + } + } + + stage('Push Docker Image for Change Request') { + when { + changeRequest() + } steps { script { - def gitCommit = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim() withCredentials([usernamePassword(credentialsId: "docker-login", usernameVariable: "DOCKER_USER", passwordVariable: "DOCKER_PASSWORD")]) { sh "docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}" - sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${gitCommit}" + sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${GIT_COMMIT}" + } + } + } + } + + stage('Push Docker Image for Main') { + when { + branch "main" + } + steps { + script { + withCredentials([usernamePassword(credentialsId: "docker-login", usernameVariable: "DOCKER_USER", passwordVariable: "DOCKER_PASSWORD")]) { + sh "docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}" + sh "docker push ${DOCKER_REGISTRY}/${DOCKER_IMAGE}:${GIT_COMMIT}" } } } From 15b228d1981a80434116f754e0f8f39e8cd63814 Mon Sep 17 00:00:00 2001 From: Mihailo Date: Fri, 7 Mar 2025 13:15:21 +0100 Subject: [PATCH 17/18] Add config file for KIND cluster --- config.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 config.yaml diff --git a/config.yaml b/config.yaml new file mode 100644 index 000000000..efa360551 --- /dev/null +++ b/config.yaml @@ -0,0 +1,11 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: +- role: control-plane + extraPortMappings: + - containerPort: 30950 + hostPort: 30950 + listenAddress: "127.0.0.1" + protocol: TCP + + From f23aa04562d84127c397bf9dc1444d11fd44e103 Mon Sep 17 00:00:00 2001 From: Mihailo Date: Fri, 7 Mar 2025 14:23:33 +0100 Subject: [PATCH 18/18] Modify Jenkins file to build image every time --- Jenkinsfile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 68a97fd90..5afd03165 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -40,7 +40,7 @@ pipeline { script { // Checkstyle with Gradle sh './gradlew checkstyleMain' - archiveArtifacts artifacts: 'build/reports/checkstyle/checkstyle.xml' + archiveArtifacts artifacts: 'build/reports/checkstyle/*.xml', allowEmptyArchive: true } } } @@ -51,7 +51,7 @@ pipeline { } steps { // Test using Gradle - sh './gradlew test' + sh './gradlew clean test' } } @@ -68,9 +68,6 @@ pipeline { } stage('Build Docker Image') { - when { - changeRequest() - } steps { script { // Build the Docker image