Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: CI Pipeline

on:
push:
branches:
- develop
- main
tags:
- 'v*'


env:
DOCKERHUB_USERNAME: threeamigoscoding

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK 25
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '25'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@0b6dd653ba04f4f93bf581ec31e66cbd7dcb644d

- name: Build with Gradle
run: ./gradlew clean build

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: build-artifact
path: build/libs/*.jar
retention-days: 1

publish:
needs: build
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: build-artifact
path: build/libs

- name: Generate version tag
id: version
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION_TAG=${GITHUB_REF#refs/tags/v}
elif [[ $GITHUB_REF == refs/heads/main ]]; then
SHORT_SHA=$(git rev-parse --short HEAD)
VERSION_TAG="main-${SHORT_SHA}"
else
SHORT_SHA=$(git rev-parse --short HEAD)
VERSION_TAG="develop-${SHORT_SHA}"
fi
echo "tag=$VERSION_TAG" >> $GITHUB_OUTPUT
echo "Generated version tag: $VERSION_TAG"

- name: Build and push Docker image with Kaniko
env:
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
run: |
mkdir -p /tmp/kaniko/.docker
echo "{\"auths\":{\"https://index.docker.io/v1/\":{\"auth\":\"$(echo -n ${{ env.DOCKERHUB_USERNAME }}:${DOCKERHUB_TOKEN} | base64)\"}}}" > /tmp/kaniko/.docker/config.json
docker run \
-v ${{ github.workspace }}:/workspace \
-v /tmp/kaniko/.docker:/kaniko/.docker \
gcr.io/kaniko-project/executor:latest \
--context=/workspace \
--dockerfile=/workspace/Dockerfile \
--destination=${{ env.DOCKERHUB_USERNAME }}/devoops-reservation-service:${{ steps.version.outputs.tag }} \
--destination=${{ env.DOCKERHUB_USERNAME }}/devoops-reservation-service:latest \
--cache=true \
--cache-repo=${{ env.DOCKERHUB_USERNAME }}/devoops-reservation-service-cache
27 changes: 27 additions & 0 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: PR Check

on:
pull_request:
branches:
- develop
- main

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up JDK 25
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '25'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Build with Gradle
run: ./gradlew clean build
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ out/
.vscode/

### Mac ###
.DS_Store
.DS_Store
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM eclipse-temurin:25-jre-alpine

WORKDIR /app

COPY build/libs/*SNAPSHOT.jar app.jar

RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

EXPOSE 8080
EXPOSE 9090

ENTRYPOINT ["java", "-jar", "app.jar"]
83 changes: 79 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import com.google.protobuf.gradle.*

plugins {
java
jacoco
id("org.springframework.boot") version "4.0.1"
id("io.spring.dependency-management") version "1.1.7"
id("com.google.protobuf") version "0.9.4"
}

group = "com.devoops"
Expand All @@ -18,18 +22,89 @@ repositories {
mavenCentral()
}

val grpcVersion = "1.68.0"

dependencies {
implementation("org.springframework.boot:spring-boot-starter-flyway")
implementation("org.springframework.boot:spring-boot-starter-security")
// Web and Core
implementation("org.springframework.boot:spring-boot-starter-webmvc")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-amqp")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")

// Database
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-flyway")
implementation("org.flywaydb:flyway-database-postgresql")
runtimeOnly("org.postgresql:postgresql")
testImplementation("org.springframework.boot:spring-boot-starter-flyway-test")
testImplementation("org.springframework.boot:spring-boot-starter-security-test")

// Lombok
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")

// MapStruct
implementation("org.mapstruct:mapstruct:1.6.3")
annotationProcessor("org.mapstruct:mapstruct-processor:1.6.3")
annotationProcessor("org.projectlombok:lombok-mapstruct-binding:0.2.0")

// gRPC Server and Client
implementation("net.devh:grpc-server-spring-boot-starter:3.1.0.RELEASE")
implementation("net.devh:grpc-client-spring-boot-starter:3.1.0.RELEASE")
implementation("io.grpc:grpc-protobuf:$grpcVersion")
implementation("io.grpc:grpc-stub:$grpcVersion")
implementation("io.grpc:grpc-netty-shaded:$grpcVersion")
compileOnly("javax.annotation:javax.annotation-api:1.3.2")

// Prometheus
implementation("io.micrometer:micrometer-registry-prometheus")

// Tracing (Zipkin)
implementation("org.springframework.boot:spring-boot-micrometer-tracing-brave")
implementation("org.springframework.boot:spring-boot-starter-zipkin")
implementation("io.micrometer:micrometer-tracing-bridge-brave")
implementation("io.zipkin.reporter2:zipkin-reporter-brave")

// Logging
implementation("net.logstash.logback:logstash-logback-encoder:8.0")

// Test
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test")
testImplementation("org.springframework.boot:spring-boot-starter-flyway-test")
testImplementation("org.testcontainers:junit-jupiter:1.20.4")
testImplementation("org.testcontainers:postgresql:1.20.4")
testImplementation("io.rest-assured:rest-assured:5.5.0")
testCompileOnly("org.projectlombok:lombok")
testAnnotationProcessor("org.projectlombok:lombok")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.25.5"
}
plugins {
id("grpc") {
artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
}
}
generateProtoTasks {
all().forEach { task ->
task.plugins {
id("grpc")
}
}
}
}

tasks.withType<Test> {
useJUnitPlatform()
finalizedBy(tasks.jacocoTestReport)
}

tasks.jacocoTestReport {
dependsOn(tasks.test)
reports {
xml.required = true
}
}
21 changes: 21 additions & 0 deletions environment/.local.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
SERVER_PORT=8080
LOGSTASH_HOST=logstash:5000
ZIPKIN_HOST=zipkin
ZIPKIN_PORT=9411
POSTGRES_HOST=devoops-postgres
POSTGRES_PORT=5432
DB_USERNAME=reservation-service
DB_PASSWORD=reservation-service-pass

# gRPC Server
GRPC_PORT=9090

# gRPC Client
ACCOMMODATION_GRPC_HOST=devoops-accommodation-service
ACCOMMODATION_GRPC_PORT=9090

# RabbitMQ
RABBITMQ_HOST=devoops-rabbitmq
RABBITMQ_PORT=5672
RABBITMQ_USERNAME=devoops
RABBITMQ_PASSWORD=devoops123
55 changes: 55 additions & 0 deletions environment/helm/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
fullnameOverride: devoops-reservation-service
replicaCount: 1

image:
registry: docker.io
repository: threeamigoscoding/devoops-reservation-service
tag: "latest"
pullPolicy: IfNotPresent

service:
type: ClusterIP
httpPort: 8080
grpc:
enabled: true
port: 9090

ingress:
enabled: false

resources:
requests:
memory: 256Mi
cpu: 250m
limits:
memory: 512Mi
cpu: 1000m

health:
path: /actuator/health
periodSeconds: 10
failureThreshold: 3
startup:
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 60

configData:
JAVA_TOOL_OPTIONS: "-XX:+UseSerialGC -Xms128m -Xmx384m -XX:ActiveProcessorCount=1"
SERVER_PORT: "8080"
LOGSTASH_HOST: "devoops-logstash:5000"
ZIPKIN_HOST: "devoops-jaeger"
ZIPKIN_PORT: "9411"
POSTGRES_HOST: "devoops-postgres"
POSTGRES_PORT: "5432"
GRPC_PORT: "9090"
ACCOMMODATION_GRPC_HOST: "devoops-accommodation-service"
ACCOMMODATION_GRPC_PORT: "9090"
RABBITMQ_HOST: "devoops-rabbitmq"
RABBITMQ_PORT: "5672"

secretData:
DB_USERNAME: "reservation-service"
DB_PASSWORD: "reservation-service-pass"
RABBITMQ_USERNAME: "devoops"
RABBITMQ_PASSWORD: "devoops123"
Empty file modified gradlew
100644 → 100755
Empty file.
29 changes: 29 additions & 0 deletions src/main/java/com/devoops/reservation/config/RabbitMQConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.devoops.reservation.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitMQConfig {

@Value("${rabbitmq.exchange.notification}")
private String notificationExchange;

@Bean
public TopicExchange notificationExchange() {
return new TopicExchange(notificationExchange);
}

@Bean
public MessageConverter jsonMessageConverter() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
return new Jackson2JsonMessageConverter(objectMapper);
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/devoops/reservation/config/RequireRole.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.devoops.reservation.config;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {
String[] value();
}
Loading