Saltar al contenido
mypipelines
Java (Spring Boot)·Reusable workflow·on: workflow_call

Java Architecture

Java - Architecture Validation

.github/workflows/java-architecture.yml

.github/workflows/java-architecture.yml
name: Java - Architecture Validation
on:
workflow_call:
inputs:
runner:
description: 'Runner type'
required: false
type: string
default: 'ubuntu-latest'
container_image:
description: >-
Run the job inside this image (e.g.
ghcr.io/codehunters-io/ci-base-images:1.0.0). Empty = plain runner
with actions/setup-java. The image already carries the JDK, so the
per-run download is skipped and the version is pinned to the tag.
Gradle still comes from ./gradlew, and setup-gradle still runs for
its dependency cache.
required: false
type: string
default: ''
java_version:
description: 'Java version (ignored when container_image is set)'
required: false
type: string
default: '21'
java_distribution:
description: 'Java distribution'
required: false
type: string
default: 'temurin'
upload_diagrams:
description: 'Upload architecture diagrams as artifact'
required: false
type: boolean
default: false
artifact_retention_days:
description: 'Days to retain architecture artifacts'
required: false
type: number
default: 30
outputs:
arch_test_result:
description: 'Architecture test result (success/failure)'
value: ${{ jobs.architecture.outputs.arch_test_result }}
diagrams_artifact_name:
description: 'Name of uploaded diagrams artifact'
value: ${{ jobs.architecture.outputs.diagrams_artifact }}
# Least privilege for what this workflow actually does. Without it the
# job inherits whatever the calling repository's default happens to be,
# which on older repositories is write-all.
permissions:
contents: read
packages: read
jobs:
architecture:
name: Architecture Validation
runs-on: ${{ inputs.runner }}
# `container:` takes an object or nothing at all, and there is no way to
# write "no container" as a string. fromJSON('null') is how you say it.
container: ${{ inputs.container_image != '' && fromJSON(format('{{"image":"{0}"}}', inputs.container_image)) || fromJSON('null') }}
timeout-minutes: 15
outputs:
arch_test_result: ${{ steps.arch-test.outcome }}
diagrams_artifact: ${{ steps.diagrams-info.outputs.name }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
- name: Setup JDK ${{ inputs.java_version }}
if: inputs.container_image == ''
uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1
with:
distribution: ${{ inputs.java_distribution }}
java-version: ${{ inputs.java_version }}
- name: Report toolchain (container)
if: inputs.container_image != ''
run: |
echo "Container: ${{ inputs.container_image }}"
java -version
- name: Setup Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/master' }}
# ============================================
# ARCHUNIT ARCHITECTURE TESTS
# ============================================
- name: Run architecture tests
id: arch-test
env:
GH_PACKAGES_USERNAME: ${{ secrets.GH_PACKAGES_USERNAME }}
GH_PACKAGES_TOKEN: ${{ secrets.GH_PACKAGES_TOKEN }}
run: |
echo "Running ArchUnit architecture validation..."
./gradlew test --no-daemon --build-cache --parallel
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Architecture Tests" >> $GITHUB_STEP_SUMMARY
echo "ArchUnit validation passed." >> $GITHUB_STEP_SUMMARY
# ============================================
# STRUCTURIZR C4 DIAGRAMS
# ============================================
- name: Export Structurizr C4 diagrams
id: structurizr
run: |
if ./gradlew tasks --all --no-daemon 2>/dev/null | grep -q "structurizrExport"; then
echo "Running Structurizr C4 export..."
./gradlew structurizrExport --no-daemon --build-cache
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Structurizr C4 Diagrams" >> $GITHUB_STEP_SUMMARY
echo "C4 diagrams exported to PlantUML and Mermaid formats." >> $GITHUB_STEP_SUMMARY
else
echo "structurizrExport task not found, skipping."
fi
# ============================================
# PLANTUML CLASS/PACKAGE DIAGRAMS
# ============================================
- name: Generate class and package diagrams
id: class-diagrams
run: |
if ./gradlew tasks --all --no-daemon 2>/dev/null | grep -q "classDiagram"; then
echo "Generating PlantUML class and package diagrams..."
./gradlew classDiagram packageDiagram --no-daemon --build-cache || true
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Class & Package Diagrams" >> $GITHUB_STEP_SUMMARY
echo "PlantUML diagrams generated." >> $GITHUB_STEP_SUMMARY
else
echo "classDiagram task not found, skipping."
fi
# ============================================
# UPLOAD ARCHITECTURE ARTIFACTS
# ============================================
- name: Get diagrams artifact info
id: diagrams-info
if: inputs.upload_diagrams
run: |
echo "name=architecture-diagrams-${{ github.run_id }}" >> $GITHUB_OUTPUT
- name: Upload architecture diagrams
if: inputs.upload_diagrams && always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ steps.diagrams-info.outputs.name }}
path: architecture/
if-no-files-found: warn
retention-days: ${{ inputs.artifact_retention_days }}