From acb8a0e5d2c047c128fb449c40e4f326175674bb Mon Sep 17 00:00:00 2001 From: Ole <12736698+ole4ryb@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:51:31 +0000 Subject: [PATCH] NIAD-3278: Adding a GitHub Actions workflow so that we can replace Jenkins. (#189) * initial changes * file location change * adding tests and integration tests to GH Actions * changing jacoco report dependency * docker image correction * adding a missing docker logs script * checkout repo * building docker image step * adding a missing build id file * removing non-existent repo * refactoring * removing gradle as we use gradlew * unnecessary gradle setup as we use gradlew instead * adding checkstyle and spotbugs integration checks * adding build id comment * refactoring to get build id and publish a comment * fixing a broken link * fixing id mismatch * writing values to GH output * removing unnecessary block of script --- .github/workflows/build_workflow.yml | 277 ++++++++++++++++++ scripts/create_build_id.sh | 27 ++ scripts/dump_docker_logs.sh | 10 + service/build.gradle | 4 +- .../testcontainers/GpccMocksContainer.java | 2 +- 5 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build_workflow.yml create mode 100644 scripts/create_build_id.sh create mode 100644 scripts/dump_docker_logs.sh diff --git a/.github/workflows/build_workflow.yml b/.github/workflows/build_workflow.yml new file mode 100644 index 00000000..8445952a --- /dev/null +++ b/.github/workflows/build_workflow.yml @@ -0,0 +1,277 @@ +name: GPCC Build Workflow +on: + pull_request: + types: [opened, synchronize, reopened] + branches: + - main + push: + branches: + - main + +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: + GPC_CONSUMER_SERVER_PORT: "8090" + GPC_CONSUMER_SDS_URL: "http://wiremock:8080/spine-directory/" + GPC_CONSUMER_SDS_APIKEY: "anykey" + GPC_CONSUMER_LOGGING_LEVEL: DEBUG + run: | + docker network create commonforgpc + docker compose build + docker compose up gpc-consumer gpcc-mocks gpconnect-db gpconnect-api tkw gpcc-nginx --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 commonforgpc + 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 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + 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/main" ]]; then + GIT_BRANCH=main + 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: gpc-consumer + build-context: . + + 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: gpc_consumer_github_action_build_workflow + aws-region: ${{ secrets.AWS_REGION }} + + - 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 aced3340..3b7721a7 100644 --- a/service/build.gradle +++ b/service/build.gradle @@ -57,6 +57,9 @@ test { } jacocoTestReport { + reports { + xml.required = true + } dependsOn test // tests are required to run before generating the report } @@ -99,7 +102,6 @@ tasks.withType(Test) { } check.dependsOn integrationTest -jacocoTestReport.dependsOn integrationTest spotbugsTest.enabled = false spotbugsIntegrationTest.enabled = false diff --git a/service/src/intTest/java/uk/nhs/adaptors/gpc/consumer/testcontainers/GpccMocksContainer.java b/service/src/intTest/java/uk/nhs/adaptors/gpc/consumer/testcontainers/GpccMocksContainer.java index c3ed6152..812be698 100644 --- a/service/src/intTest/java/uk/nhs/adaptors/gpc/consumer/testcontainers/GpccMocksContainer.java +++ b/service/src/intTest/java/uk/nhs/adaptors/gpc/consumer/testcontainers/GpccMocksContainer.java @@ -19,7 +19,7 @@ public final class GpccMocksContainer extends GenericContainer