引言
于医疗互通之境,InterSystems Health Connect 往往涵蕴要旨之素,若产物、业程、运作、服事、用物之属、例程,及他 ObjectScript 之遗物。向者,多部署此等素,皆以手为之,或摹类,或引 XML,或用管理之户之器。
此法或可暂济一时,然项目日增,众匠并作,或需周流于开发、集成、预产、量产诸境而反复部署,则维繫维艰矣。
更坚卓之选,乃将 Health Connect 融于 持续集成之中。流,以Git为源代码库,以Jenkins为部署协调者。
此文旨在于示一实用之法:
- 于 GitHub 上版本 Health Connect 之代码。
- 唯检自上次部署后所改之文件。
- 将此诸文件移至预演之匣。
- 载变编译于健康连接名域。
- 以SSH之术,于Jenkins远控全程。
架构
吾例中,已设如下诸元:
IRIS为健康之实例
吾已于AWS之机,以RHEL10之系,部署InterSystems IRIS for Health,自设Apache之服务器,使HTTP与SSH之连络得通。
为治之,吾已设 Visual Studio Code 以治 IRIS 之本地实例,于其上更制代码,既成则上之 GitHub。
GitHub 之库
吾等择 GitHub 为版本管制之器,用 Visual Studio Code 所具之延展。此可使吾等若需,得治分支。
此要素乃CI/CD之要,盖因于此得最新之码以供部署也。
Jenkins(杰森)
诸君若不知Jenkins者,此乃开源自动化之服务器,广用于持续集成之程,以其插件繁众,使事易成。
Jenkins有Groovy脚本之具,使吾等得施集成之必要诸务。此例中,不须繁复。
集成之序
此例中,吾等设吾辈从事于互操作性之项目,与一 DEVELOPMENT 实例(部署于 AWS 服务器)相合,欲将开发者于其本地实例所改之变,部署以试之。其步骤大略如下:
- 开发者于其本地实例中实施其功能。
- 开发者将所改之变上传至 GitHub 仓库之相应分支。
- 其司部署者,入Jenkins而发其管.
- Jenkins以SSH连 DEVELOPMENT之伺.
- 伺上,Linux之脚本正行.
- 脚本以git pull,自库下载其新变.
- 此脚本辨新或易之文,而徙诸伺之录.
- 既辨文件,则脚本召 ObjectScript 中之次脚本。
- 次脚本载编诸文件于IRIS for Health之实例。
- 若上传得宜,则脚本重启生产。
如君所见,吾等择一甚简之术,然其用颇为有益。
今且观吾等将藉Jenkins于开发之服务器上所运行之脚本也。
#!/usr/bin/env bash
set -euo pipefail
=========================
Configuration
=========================
REPO_URL="https://github.com/intersystems-ib/workshop-cicd-demo"
BRANCH="main"
Local clone used to compare commits
CACHE_REPO="/opt/git-cache/project_repo"
Folder to copy the files to be uploaded into Health Connect
EXPORT_DIR="/projectGit"
File with the latest processed commit
STATE_FILE="${CACHE_REPO}/.last_sync_commit"
CLean up EXPORT_DIR before to copy the new updates
CLEAN_EXPORT_DIR="true"
=========================
Validations
=========================
if ! command -v git >/dev/null 2>&1; then
echo "Error: git is not installed."
exit 1
fi
mkdir -p "${EXPORT_DIR}"
mkdir -p "$(dirname "${CACHE_REPO}")"
=========================
Clone or update cache folder
=========================
if [ ! -d "${CACHE_REPO}/.git" ]; then
echo "Cloning repository into cache..."
git clone --branch "${BRANCH}" "${REPO_URL}" "${CACHE_REPO}"
else
echo "Updating local cache..."
git -C "${CACHE_REPO}" fetch origin
git -C "${CACHE_REPO}" checkout "${BRANCH}"
git -C "${CACHE_REPO}" reset --hard "origin/${BRANCH}"
fi
REMOTE_COMMIT="$(git -C "${CACHE_REPO}" rev-parse HEAD)"
=========================
First execution
=========================
if [ ! -f "${STATE_FILE}" ]; then
echo "First execution."
echo "Copying all the contains from branch into ${EXPORT_DIR}..."
if [ "${CLEAN_EXPORT_DIR}" = "true" ]; then
find "${EXPORT_DIR}" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
fi
rsync -av --delete --exclude ".git" "${CACHE_REPO}/" "${EXPORT_DIR}/"
echo "${REMOTE_COMMIT}" > "${STATE_FILE}"
echo "First export finished."
exit 0
fi
LAST_COMMIT="$(cat "${STATE_FILE}")"
if [ "${LAST_COMMIT}" = "${REMOTE_COMMIT}" ]; then
echo "No updates."
exit 0
fi
echo "Comparing commits:"
echo " anterior: ${LAST_COMMIT}"
echo " actual: ${REMOTE_COMMIT}"
if [ "${CLEAN_EXPORT_DIR}" = "true" ]; then
echo "Cleaning up export folder..."
find "${EXPORT_DIR}" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
fi
=========================
Export just added or modified files
=========================
while IFS= read -r -d '' status && IFS= read -r -d '' path1; do
case "${status}" in
M|A)
echo "Exporting ${status}: ${path1}"
mkdir -p "${EXPORT_DIR}/$(dirname "${path1}")"
cp -f "${CACHE_REPO}/${path1}" "${EXPORT_DIR}/${path1}"
;;
D)
# Ignoring deletes
echo "Ignoring deleted: ${path1}"
;;
R*)
IFS= read -r -d '' path2
echo "Exporting renamed: ${path1} -> ${path2}"
mkdir -p "${EXPORT_DIR}/$(dirname "${path2}")"
cp -f "${CACHE_REPO}/${path2}" "${EXPORT_DIR}/${path2}"
;;
*)
echo "Change not automatically managed: ${status} ${path1}"
;;
esac
done < <(git -C "${CACHE_REPO}" diff --name-status -z "${LAST_COMMIT}" "${REMOTE_COMMIT}")
echo "${REMOTE_COMMIT}" > "${STATE_FILE}"
echo "Incremental export concluded in ${EXPORT_DIR}"
echo "Starting file upload and compile in Health Connect"
(echo '_system'; echo 'SYS'; cat iris.script) | iris session IRISHEALTH
echo "Compilation successfully finished"
如见,此脚本执行于吾GitHub仓库之git pull,更新DEVELOPMENT服务器上之源码,察其较上次下载之异,复自其抽之至第二目录。/项目Git终乃唤 IRIS 脚本。
(echo '_system'; echo 'SYS'; cat iris.script) | iris session IRISHEALTH
彼前二者回响指令将使吾等得将用户名与密码传送至需开启之终端会话,以运行吾等之ObjectScript脚本也。
zn "DEMO"
set sc = $SYSTEM.OBJ.LoadDir("/projectGit/src/Demo", "ck", , 1)
if '$SYSTEM.Status.IsOK(sc) do $SYSTEM.Status.DisplayError(sc) quit
set production = "Demo.Order.Production"
set ^Ens.Configuration("csp","LastProduction") = production
do ##class(Ens.Director).SetAutoStart(production)
do ##class(Ens.Director).StartProduction(production)
write !,"Produccion iniciada correctamente: ",production,!
此脚本乃导入吾辈所辨为修改或新创之诸类,并为之编译。若编译得宜,则重启吾辈DEMO名域之相应生产境,俾变更得施。
善哉,吾等已得脚本, DEVELOPMENT 服务器,及 GitHub,今可配置吾等之 Jenkins。
配置Jenkins
始为管路,必先安插插件,使得能以SSH连至吾等之 DEVELOPMENT服务器(Development Server),用吾等之主用户名及密码。
自Jenkins之配置,吾辈创一访问凭信,以达吾辈之DEVELOPMENT服务器。
终乃造 Pipeline。
于管路之配置中,吾等立此脚本,以使部署之事得成。
pipeline {
agent any
parameters {
string(name: 'GIT_BRANCH', defaultValue: 'main', description: 'Repository branch')
string(name: 'REMOTE_HOST', defaultValue: 'ec2-**-**-***-**.**-*****.compute.amazonaws.com', description: 'Remote Host')
string(name: 'REMOTE_USER', defaultValue: 'ec2-user', description: 'Remote SSH user')
string(name: 'REMOTE_SCRIPT_NAME', defaultValue: 'shell_script.sh', description: 'Remote script name')
}
environment {
REPO_URL = 'https://github.com/intersystems-ib/workshop-cicd-demo'
SSH_CREDENTIALS_ID = 'ssh-healthconnect-remote'
}
stages {
stage('Checkout') {
steps {
git branch: "${params.GIT_BRANCH}", url: "${env.REPO_URL}"
}
}
stage('Validate script') {
steps {
sh '''
set -eu
test -f shell_script.sh
chmod +x shell_script.sh
'''
}
}
stage('Launch remote script') {
steps {
sshagent(credentials: ["${env.SSH_CREDENTIALS_ID}"]) {
sh '''
set -eu
ssh -o StrictHostKeyChecking=no "${REMOTE_USER}@${REMOTE_HOST}" \
"sudo sh '/${REMOTE_SCRIPT_NAME}'" | tee remote_execution.log
'''
}
}
}
}
post {
always {
archiveArtifacts artifacts: 'remote_execution.log', allowEmptyArchive: true
}
success {
echo 'Remote deployment successfully finished.'
}
failure {
echo 'Remote deployment failed. Check remote_execution.log.'
}
}
}
吾之脚本何为?甚简,先验吾GitHub仓库存否及其关联分支,继而以SSH,发令以行Linux脚本,此脚本将司下载更新吾之实例。
吾等以小例观其效。
运此程也
吾等之产,运行如常,欲更易一�件,使一参数所显之默认值异焉:

今吾欲吾等租户标识 之参数值宜为 ZZZ-999,善哉,当更吾等 Visual Studio Code 之本地实例之码,并上传此变于吾等 GitHub。
既有此变推于吾等之库,便可自吾等 Jenkins 实例运行此管。观此管之出何如:
皆无谬误;已察吾等之变,并成功执行其脚本。
吾辈当验其参数已变,且生产已复。
噫!新之租户ID已得!圆满成功!
结论与后续之步骤。
尔或已察,IRIS无技术之限,可参与持续集成之程。惟需适于日常之脚本耳。
是故,吾等于此文中睹IRIS于健康领域之持续集成小例,然此可扩之至某些配置,可藉配置合并等特性以部署之。
试之!























