diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..e8ffd8e3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,280 @@ + +name: 111 Adaptor Build Workflow +on: + pull_request: + types: [opened, synchronize, reopened] + branches: + - master + push: + branches: + - master + +jobs: + checkstyle: + name: Checkstyle + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup Java 21 LTS + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'temurin' + + - name: Checkstyle + run: | + ./gradlew checkStyleMain checkstyleTest checkstyleIntegrationTest --parallel + working-directory: ./service + + - name: Collect Artifacts + if: always() + run: | + mkdir -p artifacts + cp -r ./service/build/reports ./artifacts + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: 'Checkstyle Reports' + path: ./artifacts/** + compression-level: 9 + + - name: Temporary Artifacts Cleanup + run: rm -rf ./artifacts + + spotbugs: + name: Spotbugs + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup Java 21 LTS + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'temurin' + + - name: Spotbugs + run: | + ./gradlew spotbugsMain spotbugsTest spotbugsIntegrationTest --parallel + working-directory: ./service + + - name: Collect Artifacts + if: always() + run: | + mkdir -p artifacts + cp -r ./service/build/reports ./artifacts + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: 'Spotbugs Reports' + path: ./artifacts/** + compression-level: 9 + + - name: Temporary Artifacts Cleanup + run: rm -rf ./artifacts + + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + needs: [ checkstyle, spotbugs ] + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup Java 21 LTS + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'temurin' + + - name: Execute Unit Tests + run: ./gradlew test jacocoTestReport --parallel --build-cache + working-directory: ./service + + - name: Collect Artifacts + if: always() + run: | + mkdir -p artifacts + cp -r ./service/build/reports ./artifacts + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: 'Unit Test Reports' + path: ./artifacts/** + compression-level: 9 + + - name: Temporary Artifacts Cleanup + run: rm -rf ./artifacts + + integration-tests: + name: Integration Tests + runs-on: ubuntu-latest + needs: [ checkstyle, spotbugs ] + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup Java 21 LTS + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: 'temurin' + + - name: Start Docker Dependencies + env: + PEM111_AMQP_BROKER: "amqp://activemq:5672" + PEM111_AMQP_PORT: "5672" + PEM111_ITK_EXTERNAL_CONFIGURATION_URL: "http://wiremock:8080/configuration/ods-dos" + LOG_LEVEL: DEBUG + run: | + docker network create 111network + docker compose build + docker compose up activemq wiremock --detach + working-directory: ./docker + + - name: Execute Integration Tests + run: ./gradlew integrationTest + working-directory: ./service + + - name: Dump Docker Logs + if: always() + run: | + chmod +x dump_docker_logs.sh + ./dump_docker_logs.sh + working-directory: ./scripts + shell: bash + + - name: Collect Artifacts + if: always() + run: | + mkdir -p artifacts + cp -r ./service/build/reports ./artifacts + cp -r ./scripts/logs ./artifacts + + - name: Upload Artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: 'Integration Test Reports & Docker Logs' + path: ./artifacts/** + compression-level: 9 + + - name: Stop Docker Dependencies + if: always() + run: | + docker compose down --rmi=local --volumes --remove-orphans + docker compose rm + docker network rm 111network + working-directory: ./docker + + - name: Temporary Artifacts Cleanup + run: rm -rf ./artifacts + + generate-build-id: + name: Generate Build ID + runs-on: ubuntu-latest + needs: [unit-tests, integration-tests] + outputs: + build-id: ${{ steps.generate.outputs.buildId }} + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - id: generate + working-directory: ./scripts + shell: bash + run: | + chmod +x ./create_build_id.sh + + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + GIT_BRANCH=PR + elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == "refs/heads/master" ]]; then + GIT_BRANCH=master + fi + + BUILD_ID=$(./create_build_id.sh $GIT_BRANCH ${{ github.run_number }} ${{ github.sha }}) + echo "Generated the build tag: $BUILD_ID" + echo "buildId=$BUILD_ID" >> $GITHUB_OUTPUT + + + build-and-publish-docker-images: + name: Build & Publish Docker Images + runs-on: ubuntu-latest + needs: [unit-tests, integration-tests, generate-build-id] + permissions: + id-token: write + contents: read + strategy: + matrix: + config: + - directory: service + repository: 111 + build-context: . + - directory: nginx + repository: 111-nginx + build-context: . + + if: github.actor != 'dependabot[bot]' + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ROLE_TO_ASSUME }} + role-session-name: 111_github_action_build_workflow + aws-region: ${{ secrets.AWS_REGION || 'eu-west-2' }} + + - name: Build Docker Image + run: | + # Create Docker Tag + DOCKER_REGISTRY="${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com" + DOCKER_TAG="$DOCKER_REGISTRY/${{ matrix.config.repository }}:${{ needs.generate-build-id.outputs.build-id }}" + echo "DOCKER_TAG=$DOCKER_TAG" >> $GITHUB_ENV + + # Build Image + docker build -f ./docker/${{ matrix.config.directory }}/Dockerfile -t $DOCKER_TAG ${{ matrix.config.build-context }} + + - name: Login to AWS ECR + run: | + DOCKER_REGISTRY="https://${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com" + aws ecr get-login-password --region ${{ secrets.AWS_REGION }} | docker login --username AWS --password-stdin $DOCKER_REGISTRY + + - name: Publish image to ECR + run: docker push $DOCKER_TAG + + - name: Logout of AWS ECR (Clean up Credentials) + if: always() + run: | + DOCKER_REGISTRY="https://${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com" + docker logout $DOCKER_REGISTRY + + comment: + if: github.event_name == 'pull_request' + name: "Create Build ID Comment" + needs: [generate-build-id] + continue-on-error: true + permissions: write-all + runs-on: [ ubuntu-latest ] + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Comment PR + uses: thollander/actions-comment-pull-request@v3 + with: + message: | + Images built and published to ECR using a Build Id of ${{ needs.generate-build-id.outputs.build-id }} + comment_tag: images-built + mode: upsert + diff --git a/scripts/create_build_id.sh b/scripts/create_build_id.sh new file mode 100644 index 00000000..13823be7 --- /dev/null +++ b/scripts/create_build_id.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +clean_tag_element() { + local tag_element="$1" + echo "${tag_element//\//-}" +} + +generate_tag() { + local clean_branch_name=$(clean_tag_element "$1") + local clean_build_id=$(clean_tag_element "$2") + local git_hash="$3" + + local tag="${clean_branch_name}-${clean_build_id}-${git_hash:0:7}" + + echo "$tag" +} + +if [[ $# -ne 3 ]]; then + echo "Usage: $0 branch_name build_id git_hash" + exit 1 +fi + +branch_name="$1" +build_id="$2" +git_hash="$3" + +generate_tag "$branch_name" "$build_id" "$git_hash" diff --git a/scripts/dump_docker_logs.sh b/scripts/dump_docker_logs.sh new file mode 100644 index 00000000..5a837134 --- /dev/null +++ b/scripts/dump_docker_logs.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +mkdir -p ./logs + +container_names=$(docker ps -a --format '{{.Names}}') + +for container in $container_names; do + docker logs "$container" > ./logs/"$container".log + echo "Logs saved for container: $container" +done \ No newline at end of file diff --git a/service/build.gradle b/service/build.gradle index 818fdf66..4057a806 100644 --- a/service/build.gradle +++ b/service/build.gradle @@ -5,6 +5,7 @@ plugins { id "io.freefair.lombok" version "8.11" id "checkstyle" id "com.github.spotbugs" version "6.0.27" + id "jacoco" } apply plugin: 'java' @@ -65,6 +66,13 @@ test { useJUnitPlatform() } +jacocoTestReport { + reports { + xml.required = true + } + dependsOn test // tests are required to run before generating the report +} + task integrationTest(type: Test) { useJUnitPlatform() { description = 'Runs integration tests.'