Skip to content

Commit

Permalink
Apply received feedback and add new features
Browse files Browse the repository at this point in the history
- Package and publish API client
- Build application image with Paketo
- Tag and publish releases (Docker image, and optionally, application JAR)
- Update documentation
  • Loading branch information
jaguililla committed Aug 14, 2024
1 parent c3d37fa commit ad95c8b
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 43 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

name: Build Branch
on:
push:
branches-ignore: [ main ]

permissions: read-all

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: SDKMAN Cache
uses: actions/cache@v4
with:
path: ~/.sdkman
key: "${{ runner.os }}-sdkman-${{ hashFiles('.sdkmanrc') }}"
restore-keys: "${{ runner.os }}-sdkman-"
- name: Maven Cache
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: "${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}"
restore-keys: "${{ runner.os }}-maven-"
- name: Install SDKMAN
run: curl -s "https://get.sdkman.io?rcupdate=false" | bash
- name: Build Application
run: |
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk env install
./mvnw
- name: Build Client
run: |
export CLIENT_PATH='target/generated-sources/openapi'
export CONTROLLERS_PATH='com/github/jaguililla/appointments/http/controllers'
rm -rf "${CLIENT_PATH}/src/main/java/${CONTROLLERS_PATH}"
mvn -f "${CLIENT_PATH}/pom.xml" clean install
25 changes: 0 additions & 25 deletions .github/workflows/push.yml

This file was deleted.

57 changes: 57 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

name: Release Application
on:
push:
branches: [ main ]

permissions: read-all

jobs:
release:
name: Release
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: SDKMAN Cache
uses: actions/cache@v4
with:
path: ~/.sdkman
key: "${{ runner.os }}-sdkman-${{ hashFiles('.sdkmanrc') }}"
restore-keys: "${{ runner.os }}-sdkman-"
- name: Maven Cache
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: "${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}"
restore-keys: "${{ runner.os }}-maven-"
- name: Install SDKMAN
run: curl -s "https://get.sdkman.io?rcupdate=false" | bash
# Required for publishing (Maven settings.xml repository)
- name: Java Setup
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: temurin
- name: Publish and Tag Application
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk env install
./mvnw -B -P release
- name: Publish Client
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
export CLIENT_PATH='target/generated-sources/openapi'
export CONTROLLERS_PATH='com/github/jaguililla/appointments/http/controllers'
export REPOSITORY='https://maven.pkg.github.com/jaguililla/spring_template'
export ALT_REPOSITORY="altDeploymentRepository=github::default::${REPOSITORY}"
rm -rf "${CLIENT_PATH}/src/main/java/${CONTROLLERS_PATH}"
mvn -f "${CLIENT_PATH}/pom.xml" -B -D ${ALT_REPOSITORY} clean deploy
100 changes: 97 additions & 3 deletions .mvn/parent.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
<openapi.package>${project.groupId}.${project.artifactId}.http</openapi.package>
<controllers.package>${openapi.package}.controllers</controllers.package>
<client.package>${openapi.package}.client</client.package>
<image.name>${project.groupId}/${project.artifactId}</image.name>
<release.goal>verify</release.goal> <!-- verify | deploy -->
<spring.server>undertow</spring.server> <!-- undertow | jetty -->
<openapi.integration>ui</openapi.integration> <!-- ui | api -->

Expand Down Expand Up @@ -108,19 +110,30 @@
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>${image.registry}/${image.name}:${project.version}</name>
<tags>
<tag>${project.groupId}/${project.artifactId}:${project.version}</tag>
<tag>${project.groupId}/${project.artifactId}:latest</tag>
<tag>${project.groupId}/${project.artifactId}</tag>
<tag>${image.registry}/${image.name}:latest</tag>
</tags>
<env>
<JAVA_TOOL_OPTIONS>
-XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:+UseNUMA
</JAVA_TOOL_OPTIONS>
<BP_JVM_JLINK_ENABLED>true</BP_JVM_JLINK_ENABLED>
<BPL_JVM_CDS_ENABLED>true</BPL_JVM_CDS_ENABLED>
<BP_SPRING_AOT_ENABLED>true</BP_SPRING_AOT_ENABLED>
<BP_JVM_VERSION>${java.version}</BP_JVM_VERSION>
</env>
</image>
</configuration>
<executions>
<execution>
<id>image</id>
<goals>
<goal>build-image</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down Expand Up @@ -207,6 +220,9 @@
<configOptions>
<useJakartaEe>true</useJakartaEe>
<openApiNullable>${openApiNullable}</openApiNullable>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}-client</artifactId>
<artifactVersion>${project.version}</artifactVersion>
</configOptions>
</configuration>
</execution>
Expand All @@ -231,5 +247,83 @@
</dependency>
</dependencies>
</profile>

<profile>
<id>release</id>

<build>
<defaultGoal>${release.goal}</defaultGoal>

<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<docker>
<publishRegistry>
<username>${env.GITHUB_ACTOR}</username>
<password>${env.GITHUB_TOKEN}</password>
</publishRegistry>
</docker>
<publish>true</publish>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<executable>git</executable>
</configuration>

<executions>
<execution>
<id>config</id>
<phase>verify</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<arguments>
<argument>config</argument>
<argument>--global</argument>
<argument>user.name</argument>
<argument>${env.GITHUB_ACTOR}</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>tag</id>
<phase>verify</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<arguments>
<argument>tag</argument>
<argument>-m</argument>
<argument>Release ${project.version}</argument>
<argument>${project.version}</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>push</id>
<phase>verify</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<arguments>
<argument>push</argument>
<argument>--tags</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
41 changes: 27 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

> # ABOUT
> # 🎯 ABOUT
> This is a 'best practices' template project. However, it is an opinionated take on that.
>
> DISCLAIMER: I'm by no means an expert on Spring Boot (it's not even my preferred tool), one reason
Expand All @@ -16,42 +16,46 @@
>
> Have fun!
# Appointments
# 🗓️ Appointments
Application to create appointments (REST API). Appointments are stored in a relational DB
(Postgres), and their creation/deletion is published to a Kafka broker.

## Architecture
* Hexagonal Architecture
## 📘 Architecture
* [Hexagonal]/[Onion]/[Clean] Architecture
* OpenAPI code generation (server and client)

## Stack
[Hexagonal]: https://alistair.cockburn.us/hexagonal-architecture
[Onion]: https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1
[Clean]: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

## 🧰 Stack
* Java 21
* Spring 3.3 (configurable server, 'undertow' by default)
* Actuator (healthcheck, etc.)
* Flyway (chosen over Liquibase for its simplicity)
* Postgres
* Kafka

## Runtime
## 🏎️ Runtime
* Cloud Native Buildpacks (building)
* Docker Compose (local environment with the infrastructure)

## Test
## 🧪 Test
* ArchUnit (preferred over Java modules: it allows naming checks, etc.)
* Testcontainers (used to provide a test instance of Postgres and Kafka)

## Development
## ⚒️ Development
* SDKMAN (allows to use simpler runners on CI)
* Maven Wrapper (Maven can be provided by SDKMAN, however, Maven Wrapper has better IDE support)
* Editorconfig (supported by a lot of editors, rules limited though)
* CI pipelines for GitHub and GitLab

## Requirements
## 📑 Requirements
* Docker Compose
* JDK 21+
* SDKMAN (optional, recommended)

## Design
## 📚 Design
* The REST API controller and client are generated from the OpenAPI spec at build time.
* Hexagonal Architecture: domain, ports, and adapters.
* Use cases are 'one responsibility services'. Start with services, split when they get bigger.
Expand All @@ -77,7 +81,16 @@ Application to create appointments (REST API). Appointments are stored in a rela
- **appointments.domain.model**: holds the business entities. These are the data structures used
by the business logic. Follows the same access rules as its parent package.

## Design Decisions
## 📖 Terms
* UseCase/Case
* Service
* Adapter
* Port
* Domain
* Input/driver adapter
* Output/driven adapter

## 🤔 Design Decisions
* Minimal: don't use libraries to implement easy stuff (even if that's boring).
* Prefer flat structure (avoid empty parent packages).
* Less coupling with Spring (easier to migrate, to other frameworks/toolkits).
Expand All @@ -92,10 +105,10 @@ Application to create appointments (REST API). Appointments are stored in a rela
a container for this application.
* Atomicity in notifiers (with outbox pattern) should be done with a different notifier adapter.

## Set up
## 🎚️ Set up
* `sdk env install`

## Commands
## ▶️ Commands
All commands assume a Unix like OS.

The most important commands to operate the project are:
Expand All @@ -110,7 +123,7 @@ To run or deploy the application:
* Run JAR locally: `java -jar target/appointments-0.1.0.jar`
* Run container: `docker-compose --profile local up`

## Service Management
## 🤖 Service Management
* You can check the API spec using [Swagger UI](http://localhost:8080/swagger-ui/index.html).

### Docker
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ services:
depends_on:
- postgres
- kafka
image: com.github.jaguililla/appointments
image: ghcr.io/jaguililla/spring_template/com.github.jaguililla/appointments
environment:
GLOBAL_LOG_LEVEL: warn
APPLICATION_LOG_LEVEL: info
Expand Down
9 changes: 9 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,17 @@
<client.package>${openapi.package}.client</client.package>
<spring.server>undertow</spring.server>
<openapi.integration>ui</openapi.integration>
<image.registry>ghcr.io/jaguililla/spring_template</image.registry>
<release.goal>deploy</release.goal>
</properties>

<distributionManagement>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/jaguililla/spring_template</url>
</repository>
</distributionManagement>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down

0 comments on commit ad95c8b

Please sign in to comment.