DEV Community

vlaship
vlaship

Posted on

SpringBoot Web Service - Part 5 - Github Action

GitHub Actions provide a seamless way to integrate CI/CD into your repository, automating various tasks like running tests, building artifacts, and deploying your project.

Workflow for SNAPSHOT

This workflow is triggered on non-main branches or manually through the workflow dispatch event. It includes the following steps:

  • Run tests: Ensures that your code passes all tests.
  • Build the JAR file: Compiles your Spring Boot application.
  • Build Docker image and push it to GitHub Docker Registry: Creates a Docker image from the generated artifact and pushes it to the GitHub Container Registry.
name: Test and Build Snapshot

on:
  push:
    branches-ignore:
      - main
  workflow_dispatch:

permissions:
  contents: read
  packages: write

jobs:
  maven-verify:
    if: "!contains(github.event.head_commit.message, '[skip ci]')"

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'
          cache: maven
          cache-dependency-path: '**/pom.xml'

      - name: Verify
        run: mvn -B clean verify --file pom.xml

  maven-build:
    needs: maven-verify
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'
          cache: maven
          cache-dependency-path: '**/pom.xml'

      - name: Build
        run: mvn -B package --file pom.xml

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

  docker-build-push:
    needs: maven-build
    runs-on: ubuntu-latest
    env:
      CURRENT_VERSION: ''

    steps:
      - uses: actions/checkout@v4

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: app.jar
          path: target

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

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GHCR_PAT }}

      - name: Get Version
        run: echo "CURRENT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV

      - name: Build Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ env.CURRENT_VERSION }}-${{ github.run_id }}
Enter fullscreen mode Exit fullscreen mode

Workflow for RELEASE

This workflow runs when changes are pushed to the main branch and includes the following steps:

  • Build the release version: Compiles the release version of your project.
  • Build Docker image and push it to GitHub Docker Registry: Creates and pushes the Docker image to the GitHub Container Registry.
  • Increment SNAPSHOT version: Updates the version in pom.xml for future snapshot versions.
name: Build Release

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  contents: read
  packages: write

jobs:
  maven-build-release:
    if: "!contains(github.event.head_commit.message, '[skip ci]')"

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'
          cache: maven
          cache-dependency-path: '**/pom.xml'

      - name: Prepare Release Version
        run: mvn versions:set -DremoveSnapshot

      - name: Build
        run: mvn -B clean package --file pom.xml -DskipTests

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

  docker-build-push:
    needs: maven-build-release
    runs-on: ubuntu-latest
    env:
      CURRENT_VERSION: ''

    steps:
      - uses: actions/checkout@v4

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: app.jar
          path: target

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

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GHCR_PAT }}

      - name: Get Version
        run: |
          mvn versions:set -DremoveSnapshot
          echo "CURRENT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV

      - name: Build Docker image
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ env.CURRENT_VERSION }}-${{ github.run_id }}

  increment-version:
    needs: docker-build-push
    runs-on: ubuntu-latest
    permissions:
      contents: write

    steps:
      - uses: actions/checkout@v4
        with:
          token: ${{ secrets.GIT_PAT }}

      - name: Configure Git
        run: |
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@users.noreply.github.com"

      - name: Increment Snapshot Version
        run: |
          # Extract current version and increment patch version
          CURRENT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
          MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1)
          MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
          PATCH=$(echo $CURRENT_VERSION | cut -d. -f3 | cut -d- -f1)
          NEW_PATCH=$((PATCH + 1))
          NEW_VERSION="$MAJOR.$MINOR.$NEW_PATCH-SNAPSHOT"

          # Update version in pom.xml
          mvn versions:set -DnewVersion=$NEW_VERSION
          mvn versions:commit

          # Commit and push the new snapshot version
          git add pom.xml
          git commit -m "Increment version to $NEW_VERSION [skip ci]"
          git push origin $(git rev-parse --abbrev-ref HEAD)
Enter fullscreen mode Exit fullscreen mode

Bonus workflow

The CodeQL workflow analyzes your Java code to identify potential vulnerabilities and issues.

name: CodeQL

on:
  pull_request:
    branches: [ "main" ]
  workflow_dispatch:

jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language: [ 'java' ]

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Java
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'
          cache: maven
          cache-dependency-path: '**/pom.xml'

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}

      - name: Autobuild
        uses: github/codeql-action/autobuild@v3

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3
        with:
          category: "/language:${{matrix.language}}"
Enter fullscreen mode Exit fullscreen mode

Updated Dockerfile

### Build stage
FROM eclipse-temurin:21-jre-alpine AS builder

# Set the working directory inside the container
WORKDIR /tmp

# Copy the source code into the container
COPY target/*.jar app.jar

# Extract the layers
RUN java -Djarmode=layertools -jar app.jar extract

### Run stage
# Create a minimal production image
FROM eclipse-temurin:21-jre-alpine

# Set the working directory inside the container
WORKDIR /app

# Set the working directory inside the container
COPY --from=builder /tmp/dependencies/ ./
COPY --from=builder /tmp/snapshot-dependencies/ ./
COPY --from=builder /tmp/spring-boot-loader/ ./
COPY --from=builder /tmp/application/ ./

# Run the binary when the container starts
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
Enter fullscreen mode Exit fullscreen mode

Top comments (0)