From 453ae7e0f8dcfc873e5bfee1a3a8c7fd9718a4a9 Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:30:49 +0200 Subject: [PATCH 01/12] feat: add NdArrayDemo entrypoint for Docker container (demo showcase of all ndarray features) --- .../sadisamir/ndarray/demo/NdArrayDemo.java | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java diff --git a/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java b/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java new file mode 100644 index 0000000..cfd5a67 --- /dev/null +++ b/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java @@ -0,0 +1,167 @@ +package org.sadisamir.ndarray.demo; + +import org.sadisamir.ndarray.NdArray; + +/** + * Demonstrates NDArray library features. + * This class serves as the entrypoint for the Docker demo container. + */ +public class NdArrayDemo { + + private static final String SEPARATOR = "─".repeat(50); + + public static void main(String[] args) { + printBanner(); + demo1DArrayCreation(); + demo2DArrayCreation(); + demoArithmeticOperations(); + demoReshape(); + demoLargeArrayDisplay(); + printFooter(); + } + + private static void printBanner() { + System.out.println(); + System.out.println("╔══════════════════════════════════════════════════╗"); + System.out.println("║ NDArray Library Feature Showcase ║"); + System.out.println("║ NumPy-inspired arrays for Java ║"); + System.out.println("╚══════════════════════════════════════════════════╝"); + System.out.println(); + } + + private static void demo1DArrayCreation() { + printSection("1D Array Creation"); + + System.out.println("Creating array from values: NdArray.array(new float[]{1, 2, 3, 4, 5})"); + NdArray arr = NdArray.array(new float[]{1f, 2f, 3f, 4f, 5f}); + System.out.println(" Result: " + arr); + System.out.println(" ndim: " + arr.getNdim()); + System.out.println(" shape: " + formatShape(arr.getShape())); + System.out.println(" size: " + arr.getSize()); + System.out.println(); + + System.out.println("Creating zeros array: NdArray.zeros(4)"); + NdArray zeros = NdArray.zeros(4); + System.out.println(" Result: " + zeros); + System.out.println(); + + System.out.println("Creating range array: NdArray.arange(0, 10, 2)"); + NdArray range = NdArray.arange(0f, 10f, 2f); + System.out.println(" Result: " + range); + System.out.println(); + } + + private static void demo2DArrayCreation() { + printSection("2D Array (Matrix) Creation"); + + System.out.println("Creating 2D array from matrix:"); + System.out.println(" NdArray.array(new float[][]{{1, 2, 3}, {4, 5, 6}})"); + NdArray matrix = NdArray.array(new float[][]{{1f, 2f, 3f}, {4f, 5f, 6f}}); + System.out.println(" Result:"); + printMatrix(matrix); + System.out.println(" ndim: " + matrix.getNdim()); + System.out.println(" shape: " + formatShape(matrix.getShape())); + System.out.println(" size: " + matrix.getSize()); + System.out.println(); + } + + private static void demoArithmeticOperations() { + printSection("Arithmetic Operations"); + + NdArray a = NdArray.array(new float[]{1f, 2f, 3f}); + NdArray b = NdArray.array(new float[]{10f, 20f, 30f}); + + System.out.println("Array a: " + a); + System.out.println("Array b: " + b); + System.out.println(); + + System.out.println("Element-wise addition: a.add(b)"); + NdArray sum = a.add(b); + System.out.println(" Result: " + sum); + System.out.println(); + + System.out.println("In-place addition: a.addInPlace(b)"); + NdArray c = NdArray.array(new float[]{1f, 2f, 3f}); + System.out.println(" Before: " + c); + c.addInPlace(b); + System.out.println(" After: " + c); + System.out.println(); + + System.out.println("2D Matrix addition:"); + NdArray m1 = NdArray.array(new float[][]{{1f, 2f}, {3f, 4f}}); + NdArray m2 = NdArray.array(new float[][]{{10f, 10f}, {10f, 10f}}); + System.out.println(" Matrix 1:"); + printMatrix(m1); + System.out.println(" Matrix 2:"); + printMatrix(m2); + System.out.println(" Sum (m1.add(m2)):"); + printMatrix(m1.add(m2)); + System.out.println(); + } + + private static void demoReshape() { + printSection("Reshape Operations"); + + System.out.println("Creating 1D array: NdArray.arange(6)"); + NdArray flat = NdArray.arange(6f); + System.out.println(" Result: " + flat); + System.out.println(" shape: " + formatShape(flat.getShape())); + System.out.println(); + + System.out.println("Reshaping to 2x3: flat.reshape(2, 3)"); + NdArray reshaped = flat.reshape(2, 3); + System.out.println(" Result:"); + printMatrix(reshaped); + System.out.println(" shape: " + formatShape(reshaped.getShape())); + System.out.println(); + + System.out.println("Reshaping to 3x2: flat.reshape(3, 2)"); + NdArray reshaped2 = flat.reshape(3, 2); + System.out.println(" Result:"); + printMatrix(reshaped2); + System.out.println(" shape: " + formatShape(reshaped2.getShape())); + System.out.println(); + } + + private static void demoLargeArrayDisplay() { + printSection("Large Array Display (Ellipsis)"); + + System.out.println("Creating large array: NdArray.arange(20)"); + NdArray large = NdArray.arange(20f); + System.out.println(" Result: " + large); + System.out.println(" (Note: Large arrays use ellipsis notation)"); + System.out.println(); + } + + private static void printSection(String title) { + System.out.println(SEPARATOR); + System.out.println("▶ " + title); + System.out.println(SEPARATOR); + System.out.println(); + } + + private static void printMatrix(NdArray matrix) { + String[] lines = matrix.toString().split("\n"); + for (String line : lines) { + System.out.println(" " + line); + } + } + + private static String formatShape(int[] shape) { + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < shape.length; i++) { + if (i > 0) sb.append(", "); + sb.append(shape[i]); + } + sb.append(")"); + return sb.toString(); + } + + private static void printFooter() { + System.out.println(SEPARATOR); + System.out.println("✓ Demo completed successfully!"); + System.out.println(" Repository: https://github.com/sMouaad/DevOps-Project"); + System.out.println(SEPARATOR); + System.out.println(); + } +} From f73e2b6a8e7cc7c18864608c45eaa90612dd842f Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:33:00 +0200 Subject: [PATCH 02/12] feat: add Dockerfile for demo container --- .dockerignore | 5 +++++ Dockerfile | 24 ++++++++++++++++++++++++ pom.xml | 13 +++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..58e2046 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +target/ +.git/ +.github/ +.gitignore +*.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8080aa8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +# Build stage: compile and package with Maven +FROM eclipse-temurin:17-jdk-alpine AS builder + +WORKDIR /build + +# Copy source and build +COPY src ./src +RUN mvn package -DskipTests -q + +# Runtime stage: minimal JRE image +FROM eclipse-temurin:17-jre-alpine + +LABEL org.opencontainers.image.title="NDArray Library Demo" \ + org.opencontainers.image.description="NumPy-inspired array library for Java - Feature Demo" \ + org.opencontainers.image.source="https://github.com/sMouaad/DevOps-Project" \ + org.opencontainers.image.vendor="sadisamir" + +WORKDIR /app + +# Copy the built JAR from builder stage +COPY --from=builder /build/target/ndarray-library-*.jar ./ndarray-demo.jar + +# Run the demo on container start +ENTRYPOINT ["java", "-jar", "ndarray-demo.jar"] diff --git a/pom.xml b/pom.xml index 70bfefe..2c17089 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,19 @@ + + org.apache.maven.plugins + maven-jar-plugin + 3.4.2 + + + + org.sadisamir.ndarray.demo.NdArrayDemo + + + + + org.jacoco jacoco-maven-plugin From c1b00e534f4455531245eae0c545d74e50264ba0 Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:33:10 +0200 Subject: [PATCH 03/12] fix: forgot to copy maven config for caching --- Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Dockerfile b/Dockerfile index 8080aa8..330991b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,11 @@ FROM eclipse-temurin:17-jdk-alpine AS builder WORKDIR /build +# Copy Maven configuration first for layer caching +COPY pom.xml . +RUN apk add --no-cache maven \ + && mvn dependency:go-offline -B + # Copy source and build COPY src ./src RUN mvn package -DskipTests -q From a6e91f6108161eb11570c6262e6777b72d6b24b7 Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:34:50 +0200 Subject: [PATCH 04/12] ci: add github action for docker build & push workflow --- .github/workflows/docker.yml | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/workflows/docker.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..bf2bf8d --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,59 @@ +name: Docker + +on: + push: + branches: + - main + tags: + - 'v*' + pull_request: + branches: + - main + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix= + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max From a1d42fc9c3038d60ae97e91e34a3d981229fcac0 Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 18:39:29 +0200 Subject: [PATCH 05/12] chore: improve readme to explain how to start the demo --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index 38f9515..cf83c37 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # NDArray Library (Java) ![CI](https://github.com/sMouaad/DevOps-Project/actions/workflows/ci.yml/badge.svg) +![Docker](https://github.com/sMouaad/DevOps-Project/actions/workflows/docker.yml/badge.svg) Small NumPy-inspired Java library for ndarray operations, developed as a DevOps team project. @@ -87,6 +88,45 @@ Planned CI quality hardening: - Optional minimum coverage threshold gate once pipeline is stable. +## Docker + +A demo container is available that showcases all NDArray features on startup. + +### Quick Start (Pull and Run) + +```bash +docker run --rm ghcr.io/smouaad/devops-project:main +``` + +### Build Locally + +```bash +# Build the image +docker build -t ndarray-demo . + +# Run the demo +docker run --rm ndarray-demo +``` + +### Image Tags + +Images are published to GitHub Container Registry (`ghcr.io/smouaad/devops-project`): + +| Tag | Description | +|-----|-------------| +| `main` | Latest build from main branch | +| `` | Semantic version (e.g., `1.0.0`, `1.0`) | +| `` | Specific commit SHA | + +### CI/CD Pipeline + +The Docker workflow (`.github/workflows/docker.yml`): + +- Builds on every push to `main` and version tags (`v*`) +- Validates builds on pull requests (no push) +- Uses multi-stage build for minimal image size +- Caches layers with GitHub Actions cache + ## Current Status vs Mandatory Scope Implemented: From 16b87715a0b82edf26f4872b435f1f25d74f2c7c Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:40:10 +0200 Subject: [PATCH 06/12] feat: should success in order to deploy docker image --- .github/workflows/ci.yml | 13 +++++++++++++ .github/workflows/docker.yml | 26 +++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef279dd..0966500 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Set up Java 17 uses: actions/setup-java@v4 @@ -27,6 +29,17 @@ jobs: - name: Run verify (tests + coverage report) run: mvn -B verify + - name: Run SonarQube analysis + env: + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + if [ -n "$SONAR_HOST_URL" ] && [ -n "$SONAR_TOKEN" ]; then + mvn -B org.sonarsource.scanner.maven:sonar-maven-plugin:sonar + else + echo "Skipping SonarQube analysis because SONAR_HOST_URL/SONAR_TOKEN are not configured." + fi + - name: Upload JaCoCo report artifacts if: always() uses: actions/upload-artifact@v4 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index bf2bf8d..75aca86 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -9,6 +9,12 @@ on: pull_request: branches: - main + workflow_run: + workflows: ["CI"] + types: + - completed + branches: + - main env: REGISTRY: ghcr.io @@ -17,6 +23,10 @@ env: jobs: build-and-push: runs-on: ubuntu-latest + if: > + (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || + (github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) || + github.event_name == 'pull_request' permissions: contents: read packages: write @@ -48,11 +58,25 @@ jobs: type=semver,pattern={{major}}.{{minor}} type=sha,prefix= + - name: Build Docker image + uses: docker/build-push-action@v6 + with: + context: . + load: true + tags: ${{ env.IMAGE_NAME }}:test + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Smoke test - verify container starts + run: | + docker run --rm ${{ env.IMAGE_NAME }}:test + - name: Build and push Docker image + if: github.event_name != 'pull_request' uses: docker/build-push-action@v6 with: context: . - push: ${{ github.event_name != 'pull_request' }} + push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha From 5da8df2cdaf4267367d25db561562f7fda123b60 Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:41:51 +0200 Subject: [PATCH 07/12] fix: github didn't like the filter syntax --- .github/workflows/docker.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 75aca86..1f66bdb 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -63,13 +63,14 @@ jobs: with: context: . load: true - tags: ${{ env.IMAGE_NAME }}:test + tags: ${{ steps.meta.outputs.tags }} cache-from: type=gha cache-to: type=gha,mode=max - name: Smoke test - verify container starts run: | - docker run --rm ${{ env.IMAGE_NAME }}:test + IMAGE_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1) + docker run --rm "$IMAGE_TAG" - name: Build and push Docker image if: github.event_name != 'pull_request' From 5c48d2948cf45a319bcfe4cd32d7a01223c1d2fa Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:56:50 +0200 Subject: [PATCH 08/12] feat: use LOGGER instead of System.out --- .../sadisamir/ndarray/demo/NdArrayDemo.java | 135 +++++++++--------- 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java b/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java index cfd5a67..165622e 100644 --- a/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java +++ b/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java @@ -1,6 +1,8 @@ package org.sadisamir.ndarray.demo; import org.sadisamir.ndarray.NdArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Demonstrates NDArray library features. @@ -8,6 +10,7 @@ */ public class NdArrayDemo { + private static final Logger LOGGER = LoggerFactory.getLogger(NdArrayDemo.class); private static final String SEPARATOR = "─".repeat(50); public static void main(String[] args) { @@ -21,48 +24,48 @@ public static void main(String[] args) { } private static void printBanner() { - System.out.println(); - System.out.println("╔══════════════════════════════════════════════════╗"); - System.out.println("║ NDArray Library Feature Showcase ║"); - System.out.println("║ NumPy-inspired arrays for Java ║"); - System.out.println("╚══════════════════════════════════════════════════╝"); - System.out.println(); + LOGGER.info(""); + LOGGER.info("╔══════════════════════════════════════════════════╗"); + LOGGER.info("║ NDArray Library Feature Showcase ║"); + LOGGER.info("║ NumPy-inspired arrays for Java ║"); + LOGGER.info("╚══════════════════════════════════════════════════╝"); + LOGGER.info(""); } private static void demo1DArrayCreation() { printSection("1D Array Creation"); - System.out.println("Creating array from values: NdArray.array(new float[]{1, 2, 3, 4, 5})"); + LOGGER.info("Creating array from values: NdArray.array(new float[]{{1, 2, 3, 4, 5}})"); NdArray arr = NdArray.array(new float[]{1f, 2f, 3f, 4f, 5f}); - System.out.println(" Result: " + arr); - System.out.println(" ndim: " + arr.getNdim()); - System.out.println(" shape: " + formatShape(arr.getShape())); - System.out.println(" size: " + arr.getSize()); - System.out.println(); + LOGGER.info(" Result: {}", arr); + LOGGER.info(" ndim: {}", arr.getNdim()); + LOGGER.info(" shape: {}", formatShape(arr.getShape())); + LOGGER.info(" size: {}", arr.getSize()); + LOGGER.info(""); - System.out.println("Creating zeros array: NdArray.zeros(4)"); + LOGGER.info("Creating zeros array: NdArray.zeros(4)"); NdArray zeros = NdArray.zeros(4); - System.out.println(" Result: " + zeros); - System.out.println(); + LOGGER.info(" Result: {}", zeros); + LOGGER.info(""); - System.out.println("Creating range array: NdArray.arange(0, 10, 2)"); + LOGGER.info("Creating range array: NdArray.arange(0, 10, 2)"); NdArray range = NdArray.arange(0f, 10f, 2f); - System.out.println(" Result: " + range); - System.out.println(); + LOGGER.info(" Result: {}", range); + LOGGER.info(""); } private static void demo2DArrayCreation() { printSection("2D Array (Matrix) Creation"); - System.out.println("Creating 2D array from matrix:"); - System.out.println(" NdArray.array(new float[][]{{1, 2, 3}, {4, 5, 6}})"); + LOGGER.info("Creating 2D array from matrix:"); + LOGGER.info(" NdArray.array(new float[][]{{{{1, 2, 3}}, {{4, 5, 6}}}})"); NdArray matrix = NdArray.array(new float[][]{{1f, 2f, 3f}, {4f, 5f, 6f}}); - System.out.println(" Result:"); + LOGGER.info(" Result:"); printMatrix(matrix); - System.out.println(" ndim: " + matrix.getNdim()); - System.out.println(" shape: " + formatShape(matrix.getShape())); - System.out.println(" size: " + matrix.getSize()); - System.out.println(); + LOGGER.info(" ndim: {}", matrix.getNdim()); + LOGGER.info(" shape: {}", formatShape(matrix.getShape())); + LOGGER.info(" size: {}", matrix.getSize()); + LOGGER.info(""); } private static void demoArithmeticOperations() { @@ -71,79 +74,79 @@ private static void demoArithmeticOperations() { NdArray a = NdArray.array(new float[]{1f, 2f, 3f}); NdArray b = NdArray.array(new float[]{10f, 20f, 30f}); - System.out.println("Array a: " + a); - System.out.println("Array b: " + b); - System.out.println(); + LOGGER.info("Array a: {}", a); + LOGGER.info("Array b: {}", b); + LOGGER.info(""); - System.out.println("Element-wise addition: a.add(b)"); + LOGGER.info("Element-wise addition: a.add(b)"); NdArray sum = a.add(b); - System.out.println(" Result: " + sum); - System.out.println(); + LOGGER.info(" Result: {}", sum); + LOGGER.info(""); - System.out.println("In-place addition: a.addInPlace(b)"); + LOGGER.info("In-place addition: a.addInPlace(b)"); NdArray c = NdArray.array(new float[]{1f, 2f, 3f}); - System.out.println(" Before: " + c); + LOGGER.info(" Before: {}", c); c.addInPlace(b); - System.out.println(" After: " + c); - System.out.println(); + LOGGER.info(" After: {}", c); + LOGGER.info(""); - System.out.println("2D Matrix addition:"); + LOGGER.info("2D Matrix addition:"); NdArray m1 = NdArray.array(new float[][]{{1f, 2f}, {3f, 4f}}); NdArray m2 = NdArray.array(new float[][]{{10f, 10f}, {10f, 10f}}); - System.out.println(" Matrix 1:"); + LOGGER.info(" Matrix 1:"); printMatrix(m1); - System.out.println(" Matrix 2:"); + LOGGER.info(" Matrix 2:"); printMatrix(m2); - System.out.println(" Sum (m1.add(m2)):"); + LOGGER.info(" Sum (m1.add(m2)):"); printMatrix(m1.add(m2)); - System.out.println(); + LOGGER.info(""); } private static void demoReshape() { printSection("Reshape Operations"); - System.out.println("Creating 1D array: NdArray.arange(6)"); + LOGGER.info("Creating 1D array: NdArray.arange(6)"); NdArray flat = NdArray.arange(6f); - System.out.println(" Result: " + flat); - System.out.println(" shape: " + formatShape(flat.getShape())); - System.out.println(); + LOGGER.info(" Result: {}", flat); + LOGGER.info(" shape: {}", formatShape(flat.getShape())); + LOGGER.info(""); - System.out.println("Reshaping to 2x3: flat.reshape(2, 3)"); + LOGGER.info("Reshaping to 2x3: flat.reshape(2, 3)"); NdArray reshaped = flat.reshape(2, 3); - System.out.println(" Result:"); + LOGGER.info(" Result:"); printMatrix(reshaped); - System.out.println(" shape: " + formatShape(reshaped.getShape())); - System.out.println(); + LOGGER.info(" shape: {}", formatShape(reshaped.getShape())); + LOGGER.info(""); - System.out.println("Reshaping to 3x2: flat.reshape(3, 2)"); + LOGGER.info("Reshaping to 3x2: flat.reshape(3, 2)"); NdArray reshaped2 = flat.reshape(3, 2); - System.out.println(" Result:"); + LOGGER.info(" Result:"); printMatrix(reshaped2); - System.out.println(" shape: " + formatShape(reshaped2.getShape())); - System.out.println(); + LOGGER.info(" shape: {}", formatShape(reshaped2.getShape())); + LOGGER.info(""); } private static void demoLargeArrayDisplay() { printSection("Large Array Display (Ellipsis)"); - System.out.println("Creating large array: NdArray.arange(20)"); + LOGGER.info("Creating large array: NdArray.arange(20)"); NdArray large = NdArray.arange(20f); - System.out.println(" Result: " + large); - System.out.println(" (Note: Large arrays use ellipsis notation)"); - System.out.println(); + LOGGER.info(" Result: {}", large); + LOGGER.info(" (Note: Large arrays use ellipsis notation)"); + LOGGER.info(""); } private static void printSection(String title) { - System.out.println(SEPARATOR); - System.out.println("▶ " + title); - System.out.println(SEPARATOR); - System.out.println(); + LOGGER.info(SEPARATOR); + LOGGER.info("▶ {}", title); + LOGGER.info(SEPARATOR); + LOGGER.info(""); } private static void printMatrix(NdArray matrix) { String[] lines = matrix.toString().split("\n"); for (String line : lines) { - System.out.println(" " + line); + LOGGER.info(" {}", line); } } @@ -158,10 +161,10 @@ private static String formatShape(int[] shape) { } private static void printFooter() { - System.out.println(SEPARATOR); - System.out.println("✓ Demo completed successfully!"); - System.out.println(" Repository: https://github.com/sMouaad/DevOps-Project"); - System.out.println(SEPARATOR); - System.out.println(); + LOGGER.info(SEPARATOR); + LOGGER.info("✓ Demo completed successfully!"); + LOGGER.info(" Repository: https://github.com/sMouaad/DevOps-Project"); + LOGGER.info(SEPARATOR); + LOGGER.info(""); } } From 998029d48284672ac448f7f9cd2296ba12bf26be Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 19:56:58 +0200 Subject: [PATCH 09/12] chore: add logger dependency (slf4j --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index 4f7b13b..ea519d5 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,16 @@ + + org.slf4j + slf4j-api + 2.0.13 + + + org.slf4j + slf4j-simple + 2.0.13 + org.junit.jupiter junit-jupiter From 2afad118ba029a6c433c02e4930c5719b7001ce0 Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:02:29 +0200 Subject: [PATCH 10/12] fix: changes asked by sonarqube are made - Added constants: RESULT_FORMAT, RESULT_LABEL, SHAPE_FORMAT - Added logShape() helper with conditional logging check - Added isInfoEnabled() guard in printMatrix() for conditional method invocation --- .../sadisamir/ndarray/demo/NdArrayDemo.java | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java b/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java index 165622e..0f347cc 100644 --- a/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java +++ b/src/main/java/org/sadisamir/ndarray/demo/NdArrayDemo.java @@ -12,6 +12,9 @@ public class NdArrayDemo { private static final Logger LOGGER = LoggerFactory.getLogger(NdArrayDemo.class); private static final String SEPARATOR = "─".repeat(50); + private static final String RESULT_FORMAT = " Result: {}"; + private static final String RESULT_LABEL = " Result:"; + private static final String SHAPE_FORMAT = " shape: {}"; public static void main(String[] args) { printBanner(); @@ -37,20 +40,20 @@ private static void demo1DArrayCreation() { LOGGER.info("Creating array from values: NdArray.array(new float[]{{1, 2, 3, 4, 5}})"); NdArray arr = NdArray.array(new float[]{1f, 2f, 3f, 4f, 5f}); - LOGGER.info(" Result: {}", arr); + LOGGER.info(RESULT_FORMAT, arr); LOGGER.info(" ndim: {}", arr.getNdim()); - LOGGER.info(" shape: {}", formatShape(arr.getShape())); + logShape(arr.getShape()); LOGGER.info(" size: {}", arr.getSize()); LOGGER.info(""); LOGGER.info("Creating zeros array: NdArray.zeros(4)"); NdArray zeros = NdArray.zeros(4); - LOGGER.info(" Result: {}", zeros); + LOGGER.info(RESULT_FORMAT, zeros); LOGGER.info(""); LOGGER.info("Creating range array: NdArray.arange(0, 10, 2)"); NdArray range = NdArray.arange(0f, 10f, 2f); - LOGGER.info(" Result: {}", range); + LOGGER.info(RESULT_FORMAT, range); LOGGER.info(""); } @@ -60,10 +63,10 @@ private static void demo2DArrayCreation() { LOGGER.info("Creating 2D array from matrix:"); LOGGER.info(" NdArray.array(new float[][]{{{{1, 2, 3}}, {{4, 5, 6}}}})"); NdArray matrix = NdArray.array(new float[][]{{1f, 2f, 3f}, {4f, 5f, 6f}}); - LOGGER.info(" Result:"); + LOGGER.info(RESULT_LABEL); printMatrix(matrix); LOGGER.info(" ndim: {}", matrix.getNdim()); - LOGGER.info(" shape: {}", formatShape(matrix.getShape())); + logShape(matrix.getShape()); LOGGER.info(" size: {}", matrix.getSize()); LOGGER.info(""); } @@ -80,7 +83,7 @@ private static void demoArithmeticOperations() { LOGGER.info("Element-wise addition: a.add(b)"); NdArray sum = a.add(b); - LOGGER.info(" Result: {}", sum); + LOGGER.info(RESULT_FORMAT, sum); LOGGER.info(""); LOGGER.info("In-place addition: a.addInPlace(b)"); @@ -107,22 +110,22 @@ private static void demoReshape() { LOGGER.info("Creating 1D array: NdArray.arange(6)"); NdArray flat = NdArray.arange(6f); - LOGGER.info(" Result: {}", flat); - LOGGER.info(" shape: {}", formatShape(flat.getShape())); + LOGGER.info(RESULT_FORMAT, flat); + logShape(flat.getShape()); LOGGER.info(""); LOGGER.info("Reshaping to 2x3: flat.reshape(2, 3)"); NdArray reshaped = flat.reshape(2, 3); - LOGGER.info(" Result:"); + LOGGER.info(RESULT_LABEL); printMatrix(reshaped); - LOGGER.info(" shape: {}", formatShape(reshaped.getShape())); + logShape(reshaped.getShape()); LOGGER.info(""); LOGGER.info("Reshaping to 3x2: flat.reshape(3, 2)"); NdArray reshaped2 = flat.reshape(3, 2); - LOGGER.info(" Result:"); + LOGGER.info(RESULT_LABEL); printMatrix(reshaped2); - LOGGER.info(" shape: {}", formatShape(reshaped2.getShape())); + logShape(reshaped2.getShape()); LOGGER.info(""); } @@ -131,7 +134,7 @@ private static void demoLargeArrayDisplay() { LOGGER.info("Creating large array: NdArray.arange(20)"); NdArray large = NdArray.arange(20f); - LOGGER.info(" Result: {}", large); + LOGGER.info(RESULT_FORMAT, large); LOGGER.info(" (Note: Large arrays use ellipsis notation)"); LOGGER.info(""); } @@ -144,9 +147,17 @@ private static void printSection(String title) { } private static void printMatrix(NdArray matrix) { - String[] lines = matrix.toString().split("\n"); - for (String line : lines) { - LOGGER.info(" {}", line); + if (LOGGER.isInfoEnabled()) { + String[] lines = matrix.toString().split("\n"); + for (String line : lines) { + LOGGER.info(" {}", line); + } + } + } + + private static void logShape(int[] shape) { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(SHAPE_FORMAT, formatShape(shape)); } } From a1803117b5be57565296df14ab8640d936117808 Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:09:10 +0200 Subject: [PATCH 11/12] test: add test to ensure demo execution completes without errors (and shush sonarqube) --- .../sadisamir/ndarray/demo/NdArrayDemoTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/java/org/sadisamir/ndarray/demo/NdArrayDemoTest.java diff --git a/src/test/java/org/sadisamir/ndarray/demo/NdArrayDemoTest.java b/src/test/java/org/sadisamir/ndarray/demo/NdArrayDemoTest.java new file mode 100644 index 0000000..544cf42 --- /dev/null +++ b/src/test/java/org/sadisamir/ndarray/demo/NdArrayDemoTest.java @@ -0,0 +1,16 @@ +package org.sadisamir.ndarray.demo; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +/** + * Tests for NdArrayDemo to ensure demo execution completes without errors. + */ +class NdArrayDemoTest { + + @Test + void testMainExecutesWithoutException() { + assertDoesNotThrow(() -> NdArrayDemo.main(new String[]{})); + } +} From 4104bb37d4b195b4af5dc0d3f2f51ae2363be211 Mon Sep 17 00:00:00 2001 From: sMouaad <93816869+sMouaad@users.noreply.github.com> Date: Sat, 4 Apr 2026 20:13:25 +0200 Subject: [PATCH 12/12] fix: jar now runs with SLF4J included to make the logger work --- .gitignore | 1 + pom.xml | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/.gitignore b/.gitignore index 2f7896d..8b8c81d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target/ +dependency-reduced-pom.xml diff --git a/pom.xml b/pom.xml index ea519d5..da8b5f4 100644 --- a/pom.xml +++ b/pom.xml @@ -73,6 +73,27 @@ + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + org.sadisamir.ndarray.demo.NdArrayDemo + + + + + + + org.jacoco jacoco-maven-plugin