Skip to content

Commit d71e1a8

Browse files
committed
Library API in Spring Boot: N-tier, JPA and Flyway, Docker, CI with the conformance suite
0 parents  commit d71e1a8

68 files changed

Lines changed: 3698 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.dockerignore‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.git/
2+
.github/
3+
.idea/
4+
.vscode/
5+
target/
6+
*.db
7+
*.db-journal
8+
*.log
9+
*.iml
10+
README.md
11+
docker-compose.yml
12+
Dockerfile
13+
.dockerignore

‎.gitattributes‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Shell scripts must keep LF line endings to run on Linux and macOS; Windows scripts keep CRLF.
2+
* text=auto
3+
mvnw text eol=lf
4+
*.sh text eol=lf
5+
*.cmd text eol=crlf

‎.github/workflows/ci.yml‎

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# CI for the Library API (Spring Boot).
2+
# On every push and pull request: build and run the unit tests, then start the API
3+
# in test mode and run the contract's conformance suite against it, once with
4+
# SQLite and once with PostgreSQL 17.
5+
6+
# The name shown in the Actions tab.
7+
name: CI
8+
9+
# What starts the workflow: any push and any pull request.
10+
on:
11+
push:
12+
pull_request:
13+
14+
# The jobs to run. Each job gets a fresh Ubuntu machine.
15+
jobs:
16+
unit-tests:
17+
# The machine the job runs on.
18+
runs-on: ubuntu-latest
19+
20+
# The steps run in order; the first failure stops the job.
21+
steps:
22+
# "uses" runs a published action. This one checks out this repository.
23+
- uses: actions/checkout@v5
24+
25+
- name: Set up Java 21
26+
uses: actions/setup-java@v5
27+
# "with" passes inputs to the action.
28+
with:
29+
distribution: temurin
30+
java-version: "21"
31+
# Keep downloaded Maven dependencies between runs.
32+
cache: maven
33+
34+
- name: Build and run the unit tests
35+
# "run" runs shell commands. chmod in case mvnw lost its execute bit on Windows.
36+
run: |
37+
chmod +x mvnw
38+
./mvnw -B verify
39+
40+
conformance:
41+
# Only start when the unit tests have passed.
42+
needs: unit-tests
43+
runs-on: ubuntu-latest
44+
45+
# Run this job once for each value in the list.
46+
strategy:
47+
# Let the other database finish even if one fails.
48+
fail-fast: false
49+
matrix:
50+
database: [sqlite, postgresql]
51+
52+
# Containers that run next to the job. The SQLite run ignores this one.
53+
services:
54+
postgres:
55+
image: postgres:17
56+
env:
57+
POSTGRES_USER: library
58+
POSTGRES_PASSWORD: library
59+
POSTGRES_DB: library
60+
ports:
61+
- 5432:5432
62+
# Wait until PostgreSQL accepts connections before the steps start.
63+
options: >-
64+
--health-cmd "pg_isready -U library -d library"
65+
--health-interval 5s --health-timeout 3s --health-retries 20
66+
67+
# Environment variables for every step. TEST_MODE=1 turns on POST /test/reset and X-Today.
68+
env:
69+
PORT: "8000"
70+
TEST_MODE: "1"
71+
DATABASE_URL: ${{ matrix.database == 'postgresql' && 'postgresql://library:library@localhost:5432/library' || 'sqlite:///library.db' }}
72+
73+
steps:
74+
- uses: actions/checkout@v5
75+
76+
- name: Check out the contract
77+
uses: actions/checkout@v5
78+
with:
79+
repository: devfoundry-training/Library_API_Contract
80+
path: contract
81+
82+
- name: Set up Java 21
83+
uses: actions/setup-java@v5
84+
with:
85+
distribution: temurin
86+
java-version: "21"
87+
cache: maven
88+
89+
- name: Set up Python for the conformance suite
90+
uses: actions/setup-python@v6
91+
with:
92+
python-version: "3.13"
93+
94+
- name: Build the jar
95+
run: |
96+
chmod +x mvnw
97+
./mvnw -B -q package -DskipTests
98+
99+
- name: Start the API
100+
run: |
101+
nohup java -jar target/library-api.jar > app.log 2>&1 &
102+
for _ in $(seq 1 90); do curl -fs http://localhost:8000/health && break; sleep 1; done
103+
104+
- name: Conformance suite (${{ matrix.database }})
105+
run: python contract/conformance/run.py --base-url http://localhost:8000
106+
107+
- name: Server log
108+
# Only when an earlier step failed.
109+
if: failure()
110+
run: cat app.log

‎.gitignore‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Maven
2+
target/
3+
.mvn/wrapper/maven-wrapper.jar
4+
5+
# Local SQLite databases
6+
*.db
7+
*.db-journal
8+
*.db-wal
9+
*.db-shm
10+
11+
# Logs
12+
*.log
13+
14+
# IDEs
15+
.idea/
16+
*.iml
17+
.vscode/
18+
.classpath
19+
.project
20+
.settings/
21+
.factorypath
22+
bin/
23+
24+
# OS
25+
.DS_Store
26+
Thumbs.db
27+
28+
# Python virtual environment (for the conformance suite)
29+
.venv/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
wrapperVersion=3.3.4
2+
distributionType=only-script
3+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip

‎Dockerfile‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Library API (Spring Boot): build the jar with the Maven wrapper, then run it on a JRE as a non-root user.
2+
# docker build -t library-api-springboot .
3+
# docker run -p 8000:8000 library-api-springboot
4+
5+
# ---- build stage ----
6+
FROM eclipse-temurin:21.0.12.1_1-jdk-noble AS build
7+
WORKDIR /src
8+
9+
# Dependencies first, so a code change does not download them again.
10+
COPY .mvn/ .mvn/
11+
COPY mvnw pom.xml ./
12+
RUN chmod +x mvnw && ./mvnw -B -q dependency:go-offline
13+
14+
COPY src/ src/
15+
RUN ./mvnw -B -q package -DskipTests
16+
17+
# ---- runtime stage ----
18+
FROM eclipse-temurin:21.0.12.1_1-jre-alpine
19+
20+
# Time zone data for Europe/London, and a user without root rights.
21+
RUN apk add --no-cache tzdata \
22+
&& addgroup -S library \
23+
&& adduser -S -G library -h /app library
24+
25+
WORKDIR /app
26+
COPY --from=build /src/target/library-api.jar app.jar
27+
RUN chown library:library /app
28+
29+
USER library
30+
ENV PORT=8000 \
31+
TZ=Europe/London
32+
EXPOSE 8000
33+
34+
# Flyway runs the migrations on start-up, then the sample data is loaded if the database is empty.
35+
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

0 commit comments

Comments
 (0)