Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/

**/.DS_Store
**/.classpath
**/.dockerignore
**/.env
**/.factorypath
**/.git
**/.gitignore
**/.idea
**/.project
**/.sts4-cache
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.next
**/.cache
**/*.dbmdl
**/*.jfm
**/charts
**/docker-compose*
**/compose.y*ml
**/Dockerfile*
**/secrets.dev.yaml
**/values.dev.yaml
**/vendor
LICENSE
README.md
**/*.class
**/*.iml
**/*.ipr
**/*.iws
**/*.log
**/.apt_generated
**/.gradle
**/.gradletasknamecache
**/.nb-gradle
**/.springBeans
**/build
**/dist
**/gradle-app.setting
**/nbbuild
**/nbdist
**/nbproject/private
**/target
*.ctxt
.mtj.tmp
.mvn/timing.properties
buildNumber.properties
dependency-reduced-pom.xml
hs_err_pid*
pom.xml.next
pom.xml.releaseBackup
pom.xml.tag
pom.xml.versionsBackup
release.properties
replay_pid*
.github/
ci/
.github/
140 changes: 123 additions & 17 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,42 +21,98 @@ jobs:

build:
runs-on: ubuntu-latest
outputs:
alpine_server_image: ${{ steps.meta.outputs.alpine_server_image }}
ubuntu_server_image: ${{ steps.meta.outputs.ubuntu_server_image }}

steps:
- uses: actions/checkout@v4

- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
java-package: 'jdk+fx'
distribution: 'zulu'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Set build metadata
id: meta
run: |
echo "alpine_server_image=oie-ci-server:alpine-temurin21-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
echo "ubuntu_server_image=oie-ci-server:ubuntu-temurin21-${GITHUB_SHA}" >> "$GITHUB_OUTPUT"
if [ "${GITHUB_REF}" = "refs/heads/main" ]; then
echo "ANT_BUILD_ARGS=" >> "$GITHUB_ENV"
else
echo "ANT_BUILD_ARGS=-DdisableSigning=true -Dcoverage=true" >> "$GITHUB_ENV"
fi

- name: Build Alpine production image
run: |
docker buildx build \
--progress=plain \
--build-arg "ANT_BUILD_ARGS=${ANT_BUILD_ARGS}" \
--cache-from type=gha,scope=oie-build \
--cache-to type=gha,scope=oie-build,mode=max \
--target jre-run \
-t "${{ steps.meta.outputs.alpine_server_image }}" \
--load \
.

- name: Build OIE (signed)
if: github.ref == 'refs/heads/main'
working-directory: server
run: ant -f mirth-build.xml
- name: Build Ubuntu production image
run: |
docker buildx build \
--progress=plain \
--build-arg "ANT_BUILD_ARGS=${ANT_BUILD_ARGS}" \
--cache-from type=gha,scope=oie-build \
--cache-to type=gha,scope=oie-build,mode=max \
--target jdk-run \
-t "${{ steps.meta.outputs.ubuntu_server_image }}" \
--load \
.

- name: Build OIE (unsigned)
if: github.ref != 'refs/heads/main'
working-directory: server
run: ant -f mirth-build.xml -DdisableSigning=true -Dcoverage=true
- name: Export build artifacts and test results
run: |
rm -rf docker-build-output
docker buildx build \
--progress=plain \
--build-arg "ANT_BUILD_ARGS=${ANT_BUILD_ARGS}" \
--cache-from type=gha,scope=oie-build \
--cache-to type=gha,scope=oie-build,mode=max \
--target build-output-export \
--output type=local,dest=docker-build-output \
.

- name: Package distribution
run: tar czf openintegrationengine.tar.gz -C server/ setup --transform 's|^setup|openintegrationengine/|'
run: tar czf openintegrationengine.tar.gz -C docker-build-output/app/server setup --transform 's|^setup|openintegrationengine/|'

- name: Create artifact
uses: actions/upload-artifact@v4
with:
name: oie-build
path: openintegrationengine.tar.gz

- name: Save Alpine server image
run: docker save "${{ steps.meta.outputs.alpine_server_image }}" | gzip > oie-server-image-alpine-temurin21.tar.gz

- name: Upload Alpine server image
uses: actions/upload-artifact@v4
with:
name: oie-server-image-alpine-temurin21
path: oie-server-image-alpine-temurin21.tar.gz

- name: Save Ubuntu server image
run: docker save "${{ steps.meta.outputs.ubuntu_server_image }}" | gzip > oie-server-image-ubuntu-temurin21.tar.gz

- name: Upload Ubuntu server image
uses: actions/upload-artifact@v4
with:
name: oie-server-image-ubuntu-temurin21
path: oie-server-image-ubuntu-temurin21.tar.gz

- name: Stage Test Results
if: (!cancelled())
run: |
mkdir -p aggregate-test-results
# Copy the directory structures
cp -r --parents */build/test-results aggregate-test-results/
cp -r --parents docker-build-output/app/client/build/test-results aggregate-test-results/
cp -r --parents docker-build-output/app/command/build/test-results aggregate-test-results/
cp -r --parents docker-build-output/app/donkey/build/test-results aggregate-test-results/
cp -r --parents docker-build-output/app/server/build/test-results aggregate-test-results/

- name: Upload Test Results
if: (!cancelled())
Expand All @@ -66,3 +122,53 @@ jobs:
path: |
aggregate-test-results/**/*.xml

docker_smoke:
runs-on: ubuntu-latest
needs: build
strategy:
fail-fast: false
matrix:
configuration:
- alpine-temurin21-derby
- alpine-temurin21-mysql
- alpine-temurin21-postgres
- alpine-temurin21-sqlserver
- ubuntu-temurin21-derby
- ubuntu-temurin21-postgres

steps:
- uses: actions/checkout@v4

- name: Download server image
uses: actions/download-artifact@v4
with:
name: ${{ startsWith(matrix.configuration, 'ubuntu-') && 'oie-server-image-ubuntu-temurin21' || 'oie-server-image-alpine-temurin21' }}

- name: Load server image
run: |
IMAGE_ARCHIVE="${{ startsWith(matrix.configuration, 'ubuntu-') && 'oie-server-image-ubuntu-temurin21.tar.gz' || 'oie-server-image-alpine-temurin21.tar.gz' }}"
gunzip -c "$IMAGE_ARCHIVE" | docker load

- name: Build runner image
run: docker build --progress=plain -t oie-ci-runner:${{ github.sha }} ci/runner

- name: Boot and tear down configuration
run: |
docker run --rm \
--add-host host.docker.internal:host-gateway \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$GITHUB_WORKSPACE:/workspace" \
oie-ci-runner:${{ github.sha }} \
--workspace /workspace \
--configuration "${{ matrix.configuration }}" \
--server-image "${{ startsWith(matrix.configuration, 'ubuntu-') && needs.build.outputs.ubuntu_server_image || needs.build.outputs.alpine_server_image }}" \
--results-root ci/test-results

- name: Upload Docker Smoke Test Results
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v4
with:
name: Test Results Docker Smoke - ${{ matrix.configuration }}
path: |
ci/test-results/**/*.xml

107 changes: 107 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# syntax=docker/dockerfile:1.19.0
# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2025 Mitch Gaffigan

# Stages:
# 1. Builder Stage: Compiles the application and resolves dependencies. Produces
# JAR files that can be deployed.
# 1a. Install dependencies
# 1b. Build the application
# 2. Runner Stage: Creates a lightweight image that runs the application using the JRE.

FROM ubuntu:noble-20251013 AS builder
WORKDIR /app
# sdkman requires bash
SHELL ["/bin/bash", "-c"]
ARG ANT_BUILD_ARGS="-DdisableSigning=true"

# Stage 1a: Install dependencies
# Install necessary tools
COPY .sdkmanrc .
RUN apt-get update\
&& apt-get install -y zip curl\
&& curl -s "https://get.sdkman.io?ci=true" | bash \
&& source "$HOME/.sdkman/bin/sdkman-init.sh" && sdk env install \
&& rm -rf /var/lib/apt/lists/*

# Stage 1b: Build the application
# Copy the entire source tree (excluding .dockerignore files), and build
COPY . .
WORKDIR /app/server
RUN source "$HOME/.sdkman/bin/sdkman-init.sh" \
&& ANT_OPTS="-Dfile.encoding=UTF8" ant -f mirth-build.xml ${ANT_BUILD_ARGS}

# Stage 1c: Present artifacts for export if not running within docker
FROM scratch AS build-output-export
COPY --from=builder /app/server/setup /app/server/setup/
COPY --from=builder /app/client/build/test-results /app/client/build/test-results/
COPY --from=builder /app/command/build/test-results /app/command/build/test-results/
COPY --from=builder /app/donkey/build/test-results /app/donkey/build/test-results/
COPY --from=builder /app/server/build/test-results /app/server/build/test-results/

##########################################
#
# Ubuntu JDK Image
#
##########################################

FROM eclipse-temurin:21.0.9_10-jdk-noble AS jdk-run

RUN groupadd engine \
&& usermod -l engine ubuntu \
&& adduser engine engine \
&& mkdir -p /opt/engine/appdata \
&& chown -R engine:engine /opt/engine

WORKDIR /opt/engine
COPY --chown=engine:engine --from=builder \
--exclude=cli-lib \
--exclude=mirth-cli-launcher.jar \
--exclude=mccommand \
--exclude=manager-lib \
--exclude=mirth-manager-launcher.jar \
--exclude=mcmanager \
/app/server/setup ./

VOLUME /opt/engine/appdata
VOLUME /opt/engine/custom-extensions
EXPOSE 8443

USER engine
ENTRYPOINT ["./configure-from-env"]
CMD ["./oieserver"]

##########################################
#
# Alpine JRE Image
#
##########################################

FROM eclipse-temurin:21.0.9_10-jre-alpine AS jre-run

# Alpine does not include bash by default, so we install it
RUN apk add --no-cache bash
# useradd and groupadd are not available in Alpine
RUN addgroup -S engine \
&& adduser -S -g engine engine \
&& mkdir -p /opt/engine/appdata \
&& chown -R engine:engine /opt/engine

WORKDIR /opt/engine
COPY --chown=engine:engine --from=builder \
--exclude=cli-lib \
--exclude=mirth-cli-launcher.jar \
--exclude=mccommand \
--exclude=manager-lib \
--exclude=mirth-manager-launcher.jar \
--exclude=mcmanager \
/app/server/setup ./

VOLUME /opt/engine/appdata
VOLUME /opt/engine/custom-extensions

EXPOSE 8443

USER engine
ENTRYPOINT ["./configure-from-env"]
CMD ["./oieserver"]
2 changes: 2 additions & 0 deletions ci/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test-results/
__pycache__/
Loading
Loading