慣性聚合 高效追讀感興趣之博客、新聞、科技資訊
閱原文 以慣性聚合開啟

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
IRIS 中以 Git 及 Jenkins 实施持续集成
InterSystems · 2026-05-24 · via DEV Community

引言

于医疗互通之境,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于健康领域之持续集成小例,然此可扩之至某些配置,可藉配置合并等特性以部署之。

试之!