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
26 changes: 13 additions & 13 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,56 +9,56 @@ on:
jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'

- name: Install Leiningen
uses: DeLaGuardo/setup-clojure@12.1
with:
lein: 2.10.0

- name: Install dependencies
run: lein deps

- name: Run tests
run: lein test

- name: Run architectural fitness checks
run: ./bin/check-architecture.sh

- name: Build uberjar
run: lein uberjar

- name: Upload uberjar artifact
uses: actions/upload-artifact@v4
with:
name: walue-uberjar
path: target/uberjar/walue-*-standalone.jar

docker-build:
needs: build-and-test
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
with:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Walue - Portfolio Evaluation Service

[![CI/CD Pipeline](https://github.com/yourusername/walue/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/yourusername/walue/actions/workflows/ci-cd.yml)
[![Architectural Fitness](https://img.shields.io/badge/Architectural%20Fitness-Checked-brightgreen.svg)](https://github.com/yourusername/walue/blob/main/src/walue/infra/fitness.clj)
[![CI/CD Pipeline](https://github.com/wagnerdevocelot/walue/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/wagnerdevocelot/walue/actions/workflows/ci-cd.yml)
[![Architectural Fitness](https://img.shields.io/badge/Architectural%20Fitness-Checked-brightgreen.svg)](https://github.com/wagnerdevocelot/walue/blob/main/src/walue/infra/fitness.clj)

A Clojure web service that implements a portfolio evaluation system using Domain-Driven Design (DDD) and Hexagonal Architecture.

Expand Down
6 changes: 3 additions & 3 deletions src/walue/adapter/http_adapter.clj
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
(cond
(and (= uri "/api/evaluate") (= method :post))
(handle-evaluate-portfolio request evaluation-service logging-service)

(and (= uri "/health") (= method :get))
(handle-health-check request)

:else
{:status 404
:body {:error "Not found"}}))))
Expand All @@ -46,7 +46,7 @@
(let [start (System/currentTimeMillis)
response (handler request)
duration (- (System/currentTimeMillis) start)]
(logging-port/log-info logging-service
(logging-port/log-info logging-service
(str "Request completed in " duration " ms with status " (:status response)))
response)))

Expand Down
2 changes: 1 addition & 1 deletion src/walue/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
(Integer/parseInt port-str)
(catch NumberFormatException _
(let [logging-service (logging-port/->LoggingService)]
(logging-port/log-warn logging-service
(logging-port/log-warn logging-service
(str "Invalid PORT environment variable value: " port-str " - using default 8080")))
8080))))

Expand Down
4 changes: 2 additions & 2 deletions src/walue/domain/evaluation.clj
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
(defn calculate-asset-score
"Calculate score for a single asset based on all criteria"
[asset criteria]
(reduce
(reduce
(fn [score criterion]
(if (evaluate-criterion asset criterion)
(+ score (or (:peso criterion) (get criterion "peso")))
Expand All @@ -58,7 +58,7 @@
(defn evaluate-portfolio
"Main domain function that evaluates a portfolio based on criteria"
[portfolio criteria]
(let [evaluated-assets (map
(let [evaluated-assets (map
(fn [asset]
{:ticker (or (:ticker asset) (get asset "ticker"))
:score (calculate-asset-score asset criteria)})
Expand Down
54 changes: 27 additions & 27 deletions src/walue/infra/fitness.clj
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
files (get-clj-files src-dir)
ns-deps (keep extract-namespace-and-deps files)
violations (atom [])]

(doseq [[ns-name deps] ns-deps]
(let [src-layer (ns-to-layer ns-name)]
(when src-layer
Expand All @@ -59,12 +59,12 @@
(when (and dep-layer
(not (contains? (get allowed-deps src-layer) dep-layer))
(not= src-layer dep-layer))
(swap! violations conj
(swap! violations conj
{:source ns-name
:source-layer src-layer
:dependency dep
:dependency-layer dep-layer})))))))

{:valid? (empty? @violations)
:violations @violations}))

Expand All @@ -75,16 +75,16 @@
files (get-clj-files src-dir)
ns-deps (keep extract-namespace-and-deps files)
violations (atom [])]

(doseq [[ns-name deps] ns-deps]
(doseq [dep deps]
(let [dep-str (str dep)]
(when-not (or (str/starts-with? dep-str "clojure.")
(str/starts-with? dep-str "walue.domain"))
(swap! violations conj
(swap! violations conj
{:namespace ns-name
:external-dependency dep})))))

{:valid? (empty? @violations)
:violations @violations}))

Expand All @@ -97,12 +97,12 @@
visited (atom #{})
path (atom [])
cycles (atom [])]

(letfn [(dfs [ns]
(when-not (contains? @visited ns)
(swap! visited conj ns)
(swap! path conj ns)

(doseq [dep (get ns-deps ns)]
(if (some #{dep} @path)
;; Encontrou um ciclo
Expand All @@ -111,13 +111,13 @@
(swap! cycles conj cycle))
;; Continue DFS
(dfs dep)))

(swap! path pop)))]

(doseq [ns (keys ns-deps)]
(reset! path [])
(dfs ns)))

{:valid? (empty? @cycles)
:cycles @cycles}))

Expand All @@ -127,15 +127,15 @@
(let [src-dir "src/walue/port"
files (get-clj-files src-dir)
violations (atom [])]

(doseq [file files]
(let [content (slurp file)
file-name (.getName file)]
(when-not (re-find #"defprotocol" content)
(swap! violations conj
(swap! violations conj
{:file file-name
:reason "Port file should define at least one protocol"}))))

{:valid? (empty? @violations)
:violations @violations}))

Expand All @@ -145,18 +145,18 @@
(let [src-dir "src/walue/adapter"
files (get-clj-files src-dir)
violations (atom [])]

(doseq [file files]
(let [content (slurp file)
file-name (.getName file)
has-port-dependency (or
has-port-dependency (or
(re-find #"require.*\[walue\.port" content)
(re-find #"walue\.port\.[a-z-]+\s+:as" content))]
(when-not has-port-dependency
(swap! violations conj
(swap! violations conj
{:file file-name
:reason "Adapter should depend on at least one port"}))))

{:valid? (empty? @violations)
:violations @violations}))

Expand All @@ -173,7 +173,7 @@
(:valid? circular-deps-result)
(:valid? interface-result)
(:valid? adapter-result))]

{:all-valid? all-valid?
:layer-dependencies layer-deps-result
:domain-purity domain-purity-result
Expand All @@ -186,9 +186,9 @@
[& args]
(let [results (run-fitness-checks)
all-valid? (:all-valid? results)]

(println "\n=== Architectural Fitness Check Results ===\n")

;; Verifica dependências entre camadas
(let [{:keys [valid? violations]} (:layer-dependencies results)]
(println "Layer Dependencies Check:" (if valid? "PASSED ✓" "FAILED ✗"))
Expand All @@ -197,39 +197,39 @@
(doseq [v violations]
(println (str " - " (:source v) " (" (name (:source-layer v)) ") depends on "
(:dependency v) " (" (name (:dependency-layer v)) ")")))))

;; Verifica pureza do domínio
(let [{:keys [valid? violations]} (:domain-purity results)]
(println "\nDomain Purity Check:" (if valid? "PASSED ✓" "FAILED ✗"))
(when-not valid?
(println " Violations:")
(doseq [v violations]
(println (str " - " (:namespace v) " depends on external " (:external-dependency v))))))

;; Verifica dependências circulares
(let [{:keys [valid? cycles]} (:circular-dependencies results)]
(println "\nCircular Dependencies Check:" (if valid? "PASSED ✓" "FAILED ✗"))
(when-not valid?
(println " Cycles detected:")
(doseq [cycle cycles]
(println (str " - " (str/join " -> " cycle))))))

;; Verifica isolamento de interfaces
(let [{:keys [valid? violations]} (:interface-isolation results)]
(println "\nInterface Isolation Check:" (if valid? "PASSED ✓" "FAILED ✗"))
(when-not valid?
(println " Violations:")
(doseq [v violations]
(println (str " - " (:file v) ": " (:reason v))))))

;; Verifica implementação de adaptadores
(let [{:keys [valid? violations]} (:adapter-implementation results)]
(println "\nAdapter Implementation Check:" (if valid? "PASSED ✓" "FAILED ✗"))
(when-not valid?
(println " Violations:")
(doseq [v violations]
(println (str " - " (:file v) ": " (:reason v))))))

(println "\nOverall Result:" (if all-valid? "PASSED ✓" "FAILED ✗"))

(System/exit (if all-valid? 0 1))))
2 changes: 1 addition & 1 deletion src/walue/infra/metrics.clj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
value-fn)

(defn get-all-metrics []
(reduce-kv
(reduce-kv
(fn [acc k v]
(let [value (cond
(= (:type v) :counter) (get-counter-value (:value v))
Expand Down
2 changes: 1 addition & 1 deletion src/walue/port/logging_port.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

(defrecord LoggingService []
LoggingPort
(log-info [_ message]
(log-info [_ message]
(println (str "{\"level\":\"info\",\"message\":\"" message "\"}")))
(log-warn [_ message]
(println (str "{\"level\":\"warn\",\"message\":\"" message "\"}")))
Expand Down
6 changes: 3 additions & 3 deletions test/walue/adapter/http_adapter_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
(mock/json-body request-body))
response (app request)
body (parse-json-body response)]

(is (= 200 (:status response)))
(is (vector? (:resultado body)))
(is (= 2 (count (:resultado body))))
Expand All @@ -60,7 +60,7 @@
request (mock/request :get "/health")
response (app request)
body (parse-json-body response)]

(is (= 200 (:status response)))
(is (= "UP" (:status body)))))

Expand All @@ -72,6 +72,6 @@
(mock/json-body {:invalid "request"}))
response (app request)
body (parse-json-body response)]

(is (= 400 (:status response)))
(is (contains? body :error))))))
Loading