Skip to content

Ci cd with GitHub action #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Jul 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
30cd472
product-api: initial api impl
mama-samba-braima Nov 19, 2024
5d5bd1e
product-api: delete by id sol
mama-samba-braima Nov 19, 2024
1ce58fb
product-api: delete and save
mama-samba-braima Nov 19, 2024
d0ad718
product-api: dto exercise sol
mama-samba-braima Nov 19, 2024
42c89dc
product-api: update sol
mama-samba-braima Nov 19, 2024
8a1f598
product-api: java bean validation
mama-samba-braima Nov 19, 2024
cffbba8
product-api: java bean validation exercise sol
mama-samba-braima Nov 19, 2024
9651f44
product-api: exceptions
mama-samba-braima Nov 19, 2024
a50b2d5
product-api: flyway and 1st migration
mama-samba-braima Nov 21, 2024
789755d
exercise 1 sol
mama-samba-braima Nov 22, 2024
fc8280f
exercise 2 sol
mama-samba-braima Nov 22, 2024
b6ab94a
exercise 3 sol
mama-samba-braima Nov 22, 2024
b408bfe
product-service-docker: Exercise jar solution
mama-samba-braima Nov 26, 2024
6966c02
product-service-docker: docker compose
mama-samba-braima Nov 26, 2024
37dd720
product-service-docker: exercise docker compose sol
mama-samba-braima Nov 26, 2024
99c7dc8
product-service-docker: jib and maven build
mama-samba-braima Nov 26, 2024
7ecc61a
testcontainers
mama-samba-braima Jun 3, 2025
3a7ff60
integration tests
mama-samba-braima Jun 26, 2025
8f237f6
build workflow
mama-samba-braima Jul 14, 2025
bb88696
add checkout and jdk actions
mama-samba-braima Jul 14, 2025
30aca28
fix typo
mama-samba-braima Jul 14, 2025
446d06f
change name to foo
mama-samba-braima Jul 14, 2025
ecb02dd
fix bug
mama-samba-braima Jul 14, 2025
5d83483
introduce bug
mama-samba-braima Jul 14, 2025
4675886
fix bug
mama-samba-braima Jul 14, 2025
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
18 changes: 18 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Build workflow
on:
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
- name: Maven Clean Verify
run: mvn -B -ntp clean verify
16 changes: 16 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Build argument for Java version
ARG JAVA_VERSION=21

# Stage 1: Build the application
FROM maven:3.9.4 AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package

# Stage 2: Run the application
FROM openjdk:${JAVA_VERSION}-jdk-slim
WORKDIR /app
COPY --from=builder /app/target/product-service.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
22 changes: 22 additions & 0 deletions docker-compose-db-only.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
services:
db-local-postgres:
container_name: jfs-postgres-local
image: postgres
environment:
POSTGRES_USER: amigoscode
POSTGRES_PASSWORD: password
POSTGRES_DB: jfs
ports:
- "5333:5432"
restart: unless-stopped
volumes:
- db-local:/data/postgres
networks:
- amigos

networks:
amigos:
driver: bridge

volumes:
db-local:
36 changes: 36 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
services:
product-service:
container_name: product
# image: amigoscode/product-service:jibMaven
build:
context: .
dockerfile: Dockerfile
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/jfs
SPRING_DATASOURCE_USERNAME: amigoscode
SPRING_DATASOURCE_PASSWORD: password
ports:
- "8090:8080"
networks:
- amigos
db:
container_name: jfs-postgres
image: postgres
environment:
POSTGRES_USER: amigoscode
POSTGRES_PASSWORD: password
POSTGRES_DB: jfs
ports:
- "5333:5432"
restart: unless-stopped
volumes:
- db:/data/postgres
networks:
- amigos

networks:
amigos:
driver: bridge

volumes:
db:
93 changes: 93 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<groupId>com.amigoscode</groupId>
<artifactId>jfs</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>java-springboot-full-stack</name>
<description>java-springboot-full-stack</description>
<url/>
Expand All @@ -28,6 +29,9 @@
</scm>
<properties>
<java.version>21</java.version>
<docker.username>amigoscode</docker.username>
<docker.image.name>product-service</docker.image.name>
<docker.image.tag/>
</properties>
<dependencies>
<dependency>
Expand All @@ -40,14 +44,103 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>product-service</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<from>
<image>eclipse-temurin:21-jre</image>
<platforms>
<platrom>
<architecture>amd64</architecture>
<os>linux</os>
</platrom>
<platrom>
<architecture>arm64</architecture>
<os>linux</os>
</platrom>
</platforms>
</from>
<to>
<image>docker.io/${docker.username}/${docker.image.name}:${docker.image.tag}</image>
<tags>
<tag>latest</tag>
</tags>
</to>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*IT.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<includes>
<include>**/*IntegrationTest.java</include>
<include>**/*IT.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>

Expand Down
34 changes: 34 additions & 0 deletions src/main/java/com/amigoscode/Main.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package com.amigoscode;

import com.amigoscode.product.Product;
import com.amigoscode.product.ProductRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.math.BigDecimal;
import java.util.UUID;

@SpringBootApplication
public class Main {
Expand All @@ -10,4 +17,31 @@ public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}

// @Bean
public CommandLineRunner commandLineRunner(
ProductRepository productRepository) {
return args -> {
Product product1 = new Product();
product1.setName("Macbook Pro");
product1.setDescription("Macbook Pro M4");
product1.setPrice(new BigDecimal(3000));
product1.setId(UUID.fromString(
"d95062e6-9f0b-4224-bc9d-d0723949848f")
);
product1.setStockLevel(100);
productRepository.save(product1);

Product product2 = new Product();
product2.setId(UUID.fromString(
"94d2cc8a-ad09-4902-a321-a6bf658e2463"
));
product2.setName("Mouse");
product2.setDescription("LG Mouse");
product2.setPrice(new BigDecimal(78));
product2.setStockLevel(1000);

productRepository.save(product2);
};
}

}
13 changes: 13 additions & 0 deletions src/main/java/com/amigoscode/exception/ErrorResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.amigoscode.exception;

import java.time.Instant;
import java.util.Map;

public record ErrorResponse(
String message,
String error,
int statusCode,
String path,
Instant timestamp,
Map<String, String> fieldErrors) {
}
88 changes: 88 additions & 0 deletions src/main/java/com/amigoscode/exception/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.amigoscode.exception;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.time.Instant;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(ResourceNotFound.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(
ResourceNotFound ex,
HttpServletRequest request
) {
ErrorResponse errorResponse = new ErrorResponse(
ex.getMessage(),
HttpStatus.NOT_FOUND.getReasonPhrase(),
HttpStatus.NOT_FOUND.value(),
request.getRequestURI(),
Instant.now(),
null
);
return new ResponseEntity<>(
errorResponse,
HttpStatus.NOT_FOUND
);
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationException(
MethodArgumentNotValidException ex,
HttpServletRequest request
) {

Map<String, String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.collect(Collectors.toMap(
FieldError::getField,
fieldError ->
Objects.requireNonNullElse(
fieldError.getDefaultMessage(),
"no error available"
)
));
ErrorResponse errorResponse = new ErrorResponse(
ex.getMessage(),
HttpStatus.BAD_REQUEST.getReasonPhrase(),
HttpStatus.BAD_REQUEST.value(),
request.getRequestURI(),
Instant.now(),
errors
);
return new ResponseEntity<>(
errorResponse,
HttpStatus.BAD_REQUEST
);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGenericException(
Exception ex,
HttpServletRequest request
) {
ErrorResponse errorResponse = new ErrorResponse(
ex.getMessage(),
HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(),
HttpStatus.INTERNAL_SERVER_ERROR.value(),
request.getRequestURI(),
Instant.now(),
null
);
return new ResponseEntity<>(
errorResponse,
HttpStatus.INTERNAL_SERVER_ERROR
);
}

}
7 changes: 7 additions & 0 deletions src/main/java/com/amigoscode/exception/ResourceNotFound.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.amigoscode.exception;

public class ResourceNotFound extends RuntimeException {
public ResourceNotFound(String message) {
super(message);
}
}
Loading