Skip to content

Commit 400cafc

Browse files
Gen-AI module - > repository, cors, testing, and dependency upgrade
Gen-AI module - > Repository query fix, test compliance upgrades, and dependency hardening
2 parents f6529c7 + 48e0cf1 commit 400cafc

File tree

11 files changed

+603
-42
lines changed

11 files changed

+603
-42
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
name: PR AI Summary
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
11+
jobs:
12+
summarize:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Get PR diff
19+
id: diff
20+
run: |
21+
BASE="${{ github.event.pull_request.base.sha }}"
22+
HEAD="${{ github.event.pull_request.head.sha }}"
23+
# Trae exactamente esos commits (evita problemas de merge-base y shallow clones)
24+
git fetch --no-tags --prune --depth=1 origin $BASE $HEAD
25+
git diff $BASE $HEAD > pr.diff
26+
echo "path=pr.diff" >> $GITHUB_OUTPUT
27+
28+
- name: Set up Python
29+
uses: actions/setup-python@v5
30+
with:
31+
python-version: '3.11'
32+
33+
- name: Install deps
34+
run: |
35+
python -m pip install --upgrade pip
36+
pip install openai==1.* # SDK oficial
37+
38+
- name: Generate AI summary (OpenAI)
39+
id: ai
40+
continue-on-error: true
41+
env:
42+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
43+
MODEL: gpt-4o-mini
44+
run: |
45+
python - << 'PY'
46+
import os
47+
from openai import OpenAI
48+
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
49+
50+
with open("pr.diff","r",encoding="utf-8") as f:
51+
diff = f.read()[:200000] # tope por costos/ruido
52+
53+
prompt = (
54+
"You are a code reviewer. Summarize this PR in 2-20 bullets. "
55+
"Include WHAT changed, WHY it matters, RISKS, TESTS to add, and any BREAKING CHANGES. "
56+
"Highlight key features or changes. Consider markdown as the default output format."
57+
"Keep in mind the following points:"
58+
"1) If DIFF shows only documentation files (e.g., .md/.mdx/.txt/README), state 'Docs-only change', "
59+
" make clear that the change is included only in documentation files, if that is the case, "
60+
" otherwise explain normally, considering the DIFF changes like normal. "
61+
"2) Include a short list of changed file paths as extracted from DIFF. "
62+
"Keep it concise and actionable.\n\nDIFF:\n" + diff
63+
)
64+
65+
resp = client.chat.completions.create(
66+
model=os.getenv("MODEL","gpt-4o-mini"),
67+
temperature=0.2,
68+
messages=[{"role":"user","content":prompt}],
69+
)
70+
text = resp.choices[0].message.content.strip()
71+
with open("summary.txt","w",encoding="utf-8") as f:
72+
f.write(text)
73+
PY
74+
75+
- name: Heuristic fallback if AI failed
76+
if: ${{ steps.ai.outcome == 'failure' }}
77+
run: |
78+
python - << 'PY'
79+
import re, pathlib
80+
diff = pathlib.Path("pr.diff").read_text(encoding="utf-8")
81+
82+
added = len(re.findall(r"^\\+[^+].*$", diff, flags=re.M))
83+
removed = len(re.findall(r"^\\-[^-].*$", diff, flags=re.M))
84+
files = re.findall(r"^\\+\\+\\+ b/(.+)$", diff, flags=re.M)
85+
86+
lower_paths = [f.lower() for f in files]
87+
DOC_EXT = (".md", ".mdx", ".txt", ".rst", ".adoc")
88+
is_doc = lambda p: p.endswith(DOC_EXT) or "/docs/" in p or "/doc/" in p
89+
docs_only = len(files) > 0 and all(is_doc(p) for p in lower_paths)
90+
91+
# ---------- Doc-only summary ----------
92+
if docs_only:
93+
bullets_changed = []
94+
for f in files[:20]: # evita listas enormes
95+
bullets_changed.append(f"- `{f}`")
96+
doc_summary = [
97+
"## PR Summary",
98+
"",
99+
"### WHAT Changed",
100+
"- **Docs-only change** detected from DIFF.",
101+
f"- Files changed ({len(files)}):",
102+
*bullets_changed,
103+
"",
104+
"### WHY It Matters",
105+
"- Improves documentation/README clarity and onboarding experience.",
106+
"",
107+
"### RISKS",
108+
"- None to runtime behavior (documentation only).",
109+
"",
110+
"### TESTS to Add",
111+
"- N/A (no code changes).",
112+
"",
113+
"### BREAKING CHANGES",
114+
"- None.",
115+
]
116+
pathlib.Path("summary.txt").write_text("\n".join(doc_summary), encoding="utf-8")
117+
raise SystemExit(0)
118+
119+
scopes = set()
120+
for f in files:
121+
fl = f.lower()
122+
if "/controller" in fl: scopes.add("controller")
123+
elif "/service" in fl: scopes.add("service")
124+
elif "/repository" in fl or "jparepository" in diff.lower(): scopes.add("repository")
125+
elif "/entity" in fl or "/model" in fl: scopes.add("entity")
126+
elif "application" in fl and (fl.endswith(".yml") or fl.endswith(".yaml") or fl.endswith(".properties")):
127+
scopes.add("config")
128+
elif fl.endswith("test.java"): scopes.add("test")
129+
130+
scope = ",".join(sorted(scopes)) if scopes else "core"
131+
kind = "refactor"
132+
if added and not removed: kind = "feat"
133+
if removed and not added: kind = "chore"
134+
if re.search(r"@Test", diff): kind = "test"
135+
if re.search(r"fix|bug|exception|stacktrace", diff, re.I): kind = "fix"
136+
137+
subject = f"[Fallback] {kind}({scope}): {len(files)} file(s), +{added}/-{removed}"
138+
139+
bullets = []
140+
bullets.append(f"- Files changed: {len(files)}")
141+
bullets.append(f"- Lines: +{added} / -{removed}")
142+
if scopes:
143+
bullets.append(f"- Layers: {', '.join(sorted(scopes))}")
144+
if re.search(r"@Transactional", diff): bullets.append("- Touches transactional boundaries")
145+
if re.search(r"@RestController|@Controller", diff): bullets.append("- Controller changes present")
146+
if re.search(r"@Service", diff): bullets.append("- Service-layer changes present")
147+
if re.search(r"@Repository|JpaRepository", diff): bullets.append("- Repository-layer changes present")
148+
if re.search(r"todo|fixme", diff, re.I): bullets.append("- Contains TODO/FIXME markers")
149+
150+
text = subject + "\\n\\n" + "\\n".join(bullets)
151+
pathlib.Path("summary.txt").write_text(text, encoding="utf-8")
152+
PY
153+
154+
- name: Comment on PR
155+
uses: marocchino/sticky-pull-request-comment@v2
156+
with:
157+
header: ai-pr-summary
158+
recreate: true
159+
path: summary.txt

README.md

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# InventoryManagerBC
2-
Breakable Toy 1 - Inventory Manager
2+
Breakable Toy 1 (Gen AI Augmented) - Inventory Manager
33

44
# Inventory Management Application
55

@@ -57,18 +57,14 @@ This is a Spring Boot-based inventory management application designed to help ma
5757
| GET | `/products/categories` | Retrieves all the categories available |
5858

5959

60-
### Storage
61-
62-
Currently, product data is stored in a local database using docker.
63-
6460
---
6561

6662
## Tech Stack
6763

6864
- **Language:** Java
6965
- **Framework:** Spring Boot
7066
- **Build Tool:** Maven
71-
- **Data Storage:** Oracle DB
67+
- **Data Storage:** H2 local Runtime via JDBC
7268

7369
---
7470

@@ -82,13 +78,5 @@ Currently, product data is stored in a local database using docker.
8278
### Running the Application
8379

8480
```bash
85-
docker run -d \
86-
--name oracle-xe \
87-
-e ORACLE_PASSWORD=admin \
88-
-p 1521:1521 \
89-
-p 5500:5500 \
90-
oracle-xe-inventory-manager:1.0
91-
```
92-
```bash
93-
mvn spring-boot:run
81+
mvn spring-boot:run
9482
```

pom.xml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>org.springframework.boot</groupId>
77
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>3.5.0</version>
8+
<version>3.5.6</version>
99
<relativePath/>
1010
</parent>
1111
<groupId>com.encorazone</groupId>
@@ -27,12 +27,14 @@
2727
<url/>
2828
</scm>
2929
<properties>
30+
<logback.version>1.5.19</logback.version>
3031
<java.version>17</java.version>
3132
<ojdbc.version>21.3.0.0</ojdbc.version>
32-
<springdoc.version>2.3.0</springdoc.version>
33+
<springdoc.version>2.8.13</springdoc.version>
3334
<lombok.version>1.18.38</lombok.version>
3435
<mapstruct.version>1.5.5.Final</mapstruct.version>
3536
<maven-compiler.version>3.14.0</maven-compiler.version>
37+
<commons-lang3.version>3.18.0</commons-lang3.version>
3638
</properties>
3739
<dependencies>
3840
<dependency>
@@ -86,11 +88,6 @@
8688
<artifactId>lombok</artifactId>
8789
<version>${lombok.version}</version>
8890
</dependency>
89-
<dependency>
90-
<groupId>com.h2database</groupId>
91-
<artifactId>h2</artifactId>
92-
<scope>test</scope>
93-
</dependency>
9491
<dependency>
9592
<groupId>org.mapstruct</groupId>
9693
<artifactId>mapstruct</artifactId>
@@ -127,11 +124,17 @@
127124
</annotationProcessorPaths>
128125
</configuration>
129126
</plugin>
130-
131127
<plugin>
132128
<groupId>org.springframework.boot</groupId>
133129
<artifactId>spring-boot-maven-plugin</artifactId>
134130
</plugin>
131+
<plugin>
132+
<groupId>org.apache.maven.plugins</groupId>
133+
<artifactId>maven-surefire-plugin</artifactId>
134+
<configuration>
135+
<argLine>-XX:+EnableDynamicAgentLoading -Xshare:off</argLine>
136+
</configuration>
137+
</plugin>
135138
</plugins>
136139
</build>
137140

src/main/java/com/encorazone/inventory_manager/controller/InventoryManagerController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import java.util.List;
1616
import java.util.UUID;
1717

18-
@CrossOrigin(origins = "http://localhost:3000")
18+
@CrossOrigin(origins = "http://localhost:8080")
1919
@RestController
2020
@RequestMapping("/products")
2121
final class InventoryManagerController {

src/main/java/com/encorazone/inventory_manager/repository/ProductRepository.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ public interface ProductRepository extends JpaRepository<Product, UUID>, JpaSpec
1515
@Query("SELECT DISTINCT p.category FROM Product p")
1616
Optional<List<String>> findDistinctCategories();
1717

18-
@Query("SELECT p.category AS category, COUNT(p) AS productsInStock, " +
19-
"SUM(p.unitPrice) AS valueInStock, AVG(p.unitPrice) AS averageValue " +
18+
@Query("SELECT p.category AS category, SUM(p.stockQuantity) AS productsInStock, " +
19+
"SUM(p.unitPrice * p.stockQuantity) AS valueInStock, AVG(p.unitPrice) AS averageValue " +
2020
"FROM Product p GROUP BY p.category")
2121
List<InventorySummaryInterface> findCategoriesSummary();
2222
}

src/main/java/com/encorazone/inventory_manager/service/InventorySummary.java

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/main/resources/application.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
server:
2+
port: 9090
3+
14
spring:
25
application:
36
name: inventory-manager-spark
@@ -15,4 +18,3 @@ spring:
1518
jpa:
1619
hibernate:
1720
ddl-auto: update
18-
show-sql: true

src/main/resources/templates/hello.html

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)