# ============================================================================= # BD FHIR National — Gitea Actions CI/CD Workflow # # Trigger: Push of a version tag matching v*.*.* (e.g. v1.0.0, v1.2.3) # Runner: Self-hosted Gitea Actions runner (separate VM, Docker installed) # Registry: Gitea Packages (built-in container registry) # # Image published to: # {GITEA_SERVER}/{GITEA_OWNER}/{GITEA_REPO}:{tag} # e.g. git.dghs.gov.bd/dghs/bd-fhir-national:v1.0.0 # # REQUIRED SECRETS (set in Gitea → Repository → Settings → Secrets): # REGISTRY_USERNAME — Gitea username with write access to packages # REGISTRY_PASSWORD — Gitea personal access token (packages:write scope) # IG_PACKAGE_B64 — BD Core IG .tgz encoded as base64 # Generate: base64 -w 0 bd.gov.dghs.core-0.2.1.tgz # # REQUIRED VARIABLES (set in Gitea → Repository → Settings → Variables): # IG_PACKAGE_FILENAME — exact filename, e.g. bd.gov.dghs.core-0.2.1.tgz # IG_VERSION — version string, e.g. 0.2.1 # # HOW TO TAG AND TRIGGER A BUILD: # git tag v1.0.0 # git push origin v1.0.0 # # HOW TO UPDATE THE IG PACKAGE FOR A NEW IG VERSION: # 1. base64 -w 0 bd.gov.dghs.core-0.3.0.tgz | copy to IG_PACKAGE_B64 secret # 2. Update IG_PACKAGE_FILENAME variable to bd.gov.dghs.core-0.3.0.tgz # 3. Update IG_VERSION variable to 0.3.0 # 4. Tag and push as normal # ============================================================================= name: Build and Publish HAPI Docker Image on: push: tags: - "v*.*.*" jobs: # --------------------------------------------------------------------------- # Job 1: Test # Runs Maven tests using TestContainers (real PostgreSQL 15, no H2). # Must pass before the image is built. A failing test never produces an image. # --------------------------------------------------------------------------- test: name: Run tests runs-on: ubuntu-latest # use your self-hosted runner label if configured # replace with: runs-on: self-hosted # if your runner has no specific label steps: - name: Checkout source uses: actions/checkout@v4 - name: Set up Java 17 uses: actions/setup-java@v4 with: java-version: "17" distribution: temurin cache: maven # TestContainers requires Docker on the runner. # Your runner VM has Docker installed — this step verifies it. - name: Verify Docker available for TestContainers run: docker info - name: Place IG package for tests # The IG package must be present before mvn test runs because # FhirServerConfig.validateIgPackagePresent() checks on startup. # Decoded from the base64 secret into the correct classpath location. run: | echo "${{ secrets.IG_PACKAGE_B64 }}" | base64 -d > \ hapi-overlay/src/main/resources/packages/${{ vars.IG_PACKAGE_FILENAME }} echo "IG package placed: $(ls -lh hapi-overlay/src/main/resources/packages/)" - name: Run Maven tests run: | mvn test \ --batch-mode \ --no-transfer-progress \ -pl hapi-overlay \ -am env: # TestContainers pulls postgres:15 from Docker Hub during tests. # If your runner has no internet access, pre-pull the image and # set TESTCONTAINERS_RYUK_DISABLED=true with a local image config. TESTCONTAINERS_RYUK_DISABLED: false - name: Upload test reports on failure if: failure() uses: actions/upload-artifact@v4 with: name: surefire-reports path: hapi-overlay/target/surefire-reports/ retention-days: 7 # --------------------------------------------------------------------------- # Job 2: Build and publish Docker image # Only runs after test job passes. # Produces image tagged with both the git tag (v1.0.0) and the version # without the v prefix (1.0.0) for docker-compose .env compatibility. # --------------------------------------------------------------------------- build-and-push: name: Build and push image runs-on: ubuntu-latest # replace with: runs-on: self-hosted if needed needs: test steps: - name: Checkout source uses: actions/checkout@v4 - name: Set up Java 17 uses: actions/setup-java@v4 with: java-version: "17" distribution: temurin cache: maven # Derive version strings from the git tag. # git tag v1.0.0 → TAG_VERSION=v1.0.0, PLAIN_VERSION=1.0.0 - name: Extract version from tag id: version run: | TAG="${GITHUB_REF_NAME}" PLAIN="${TAG#v}" echo "tag_version=${TAG}" >> $GITHUB_OUTPUT echo "plain_version=${PLAIN}" >> $GITHUB_OUTPUT echo "git_commit=${GITHUB_SHA::8}" >> $GITHUB_OUTPUT echo "build_timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_OUTPUT echo "Tag: ${TAG}, Plain: ${PLAIN}, Commit: ${GITHUB_SHA::8}" # Gitea Packages registry URL format: # {gitea_host}/v2/{owner}/{repo}/manifests/{tag} # Login uses: git.dghs.gov.bd as the registry host - name: Log in to Gitea Packages registry uses: docker/login-action@v3 with: registry: ${{ gitea.server_url != '' && gitea.server_url || 'git.dghs.gov.bd' }} username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }} # Derive registry host from Gitea server URL. # Gitea Packages image path: {host}/{owner}/{repo}:{tag} - name: Derive image name id: image run: | # Extract hostname from Gitea server URL # e.g. https://git.dghs.gov.bd → git.dghs.gov.bd REGISTRY_HOST=$(echo "${{ gitea.server_url }}" | sed 's|https\?://||' | sed 's|/.*||') OWNER="${{ gitea.repository_owner }}" REPO="${{ gitea.repository }}" REPO_NAME="${REPO##*/}" IMAGE="${REGISTRY_HOST}/${OWNER}/${REPO_NAME}" echo "registry_host=${REGISTRY_HOST}" >> $GITHUB_OUTPUT echo "image=${IMAGE}" >> $GITHUB_OUTPUT echo "Image base: ${IMAGE}" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Place IG package for Docker build run: | echo "${{ secrets.IG_PACKAGE_B64 }}" | base64 -d > \ hapi-overlay/src/main/resources/packages/${{ vars.IG_PACKAGE_FILENAME }} echo "IG package placed: $(ls -lh hapi-overlay/src/main/resources/packages/)" # Run Maven package to produce the fat JAR before Docker build. # The Dockerfile COPY expects hapi-overlay/target/bd-fhir-hapi.jar. # -DskipTests: tests already ran in the test job. - name: Build fat JAR run: | mvn package \ --batch-mode \ --no-transfer-progress \ -pl hapi-overlay \ -am \ -DskipTests echo "JAR: $(ls -lh hapi-overlay/target/bd-fhir-hapi.jar)" - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: hapi-overlay/Dockerfile push: true # Tag with both v-prefixed tag and plain version. # docker-compose .env uses the plain version: HAPI_IMAGE=....:1.0.0 # The v-prefixed tag matches the git tag for traceability. tags: | ${{ steps.image.outputs.image }}:${{ steps.version.outputs.tag_version }} ${{ steps.image.outputs.image }}:${{ steps.version.outputs.plain_version }} ${{ steps.image.outputs.image }}:latest build-args: | IG_PACKAGE=${{ vars.IG_PACKAGE_FILENAME }} BUILD_VERSION=${{ steps.version.outputs.plain_version }} GIT_COMMIT=${{ steps.version.outputs.git_commit }} BUILD_TIMESTAMP=${{ steps.version.outputs.build_timestamp }} # Layer cache: use Gitea registry as cache backend. # Speeds up subsequent builds when only source changes (not POM/deps). cache-from: type=registry,ref=${{ steps.image.outputs.image }}:buildcache cache-to: type=registry,ref=${{ steps.image.outputs.image }}:buildcache,mode=max # Provenance attestation — disable for simpler Gitea registry compatibility provenance: false - name: Print published image details run: | echo "================================================" echo "Image published successfully" echo "Registry: ${{ steps.image.outputs.registry_host }}" echo "Image: ${{ steps.image.outputs.image }}" echo "Tags:" echo " ${{ steps.version.outputs.tag_version }}" echo " ${{ steps.version.outputs.plain_version }}" echo " latest" echo "Git commit: ${{ steps.version.outputs.git_commit }}" echo "IG package: ${{ vars.IG_PACKAGE_FILENAME }}" echo "IG version: ${{ vars.IG_VERSION }}" echo "================================================" echo "" echo "To deploy on production server:" echo " nano /opt/bd-fhir-national/.env" echo " # Set: HAPI_IMAGE=${{ steps.image.outputs.image }}:${{ steps.version.outputs.plain_version }}" echo " docker compose --env-file .env pull hapi" echo " docker compose --env-file .env up -d --no-deps hapi" # Clean up the IG package from the workspace. # The runner is shared — do not leave the binary on disk between builds. - name: Clean up IG package from workspace if: always() run: | rm -f hapi-overlay/src/main/resources/packages/*.tgz echo "IG package removed from runner workspace"