慣性聚合 関心のあるブログ、ニュース、テクノロジーを効率的に追跡
原文を読む 慣性聚合で開く

おすすめ購読元

博客园 - 司徒正美
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 コードのバージョニング。
  • 最後のデプロイ以降に変更されたファイルのみを検出。
  • それらのファイルをステージングフォルダにコピー。
  • 変更を Health Connect ネームスペースにロードおよびコンパイル。
  • Jenkinsを通じてSSHを使用して完全なプロセスをリモートで実行します.

アーキテクチャ.

例として、以下の要素を設定しました.

ヘルスインスタンス用のIRIS.

私はInterSystems IRIS for HealthをAWSのRHEL10マシンにデプロイし、独自のApacheサーバーを設定し、HTTPおよびSSH経由の接続を有効にしました. 

開発のために、私はVisual Studio CodeをローカルのIRISインスタンスで動作させるように設定しました。そこでコードの変更を行い、その後GitHubにアップロードします。


GitHubリポジトリ

私たちはバージョン管理システムとしてGitHubを選びました。Visual Studio Codeで利用可能な拡張機能を活用することで、必要に応じてブランチで作業することができます。

この要素はCI/CDプロセスにとって重要で、最新のデプロイ用に開発されたコードを入手できる場所だからです。

Jenkins

Jenkinsを知らない方々のために、これはオープンソースの自動化サーバーで、継続的統合プロセスに広く使用されており、多くのプラグインがあるため、作業を簡単にすることができます。

JenkinsにはGroovyスクリプトツールがあり、私たちが統合プロセスの必要なステップを実装できるようにします。この例では、あまり複雑になりません。

統合手順

この例では、AWSサーバー上でデプロイされたDEVELOPMENTインスタンス(開発のための相互運用性プロジェクト)で作業していると仮定します。ここでは、開発者がローカルインスタンスで行った変更をテストのために対応するGitHubリポジトリのブランチにデプロイしたいと考えています。手順は概ね以下のようになります:

  • 開発者はローカルインスタンスに機能を実装します。
  • 開発者は変更を対応するGitHubリポジトリのブランチにアップロードします。
  • デプロイ責任者はJenkinsにアクセスしパイプラインを起動します.
  • JenkinsはSSH経由でDEVELOPMENTサーバーに接続します.
  • サーバー上でLinuxスクリプトが実行されています.
  • スクリプトはリポジトリから最新の変更をgit pullを使用してダウンロードします.
  • このスクリプトはサーバーディレクトリにコピーされる新規または変更されたファイルを特定します.
  • ファイルが特定されると、スクリプトはObjectScript内の2番目のスクリプトを呼び出します。
  • 2番目のスクリプトはファイルをIRIS for Healthインスタンスにロードしてコンパイルします。
  • アップロードが成功した場合、スクリプトは生産を再起動します。

ご覧の通り、私たちは非常に基本的な操作を選択しましたが、それでもかなり役立つものです。

Jenkinsを使用してDEVELOPMENTサーバーで実行するスクリプトを見てみましょう:

#!/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サーバーのディレクトリ内のソースコードを更新し、最後にダウンロードしたバージョンと比較して変更を検出し、それらを2番目のディレクトリ(/projectGit)に抽出し、最後にIRISスクリプトを呼び出します。

(echo '_system'; echo 'SYS'; cat iris.script) | iris session IRISHEALTH 

最初の2つのエココマンドは、私たちが実行する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の設定

パイプラインを作成する前に、私たちは主要なユーザー名とパスワードを使ってDEVELOPMENTサーバーにSSHで接続できるようにするプラグインをインストールする必要があります.

Jenkinsの設定から、私たちはDEVELOPMENTサーバーへのアクセス資格情報を作成しました:

最後にパイプラインを作成します。

パイプラインの設定内で、以下のスクリプトを定義します。これによりデプロイが可能になります。

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スクリプトを実行する指示を送ります。そのLinuxスクリプトは、インスタンスをダウンロードおよび更新する責任を持ちます。

小さな例で実際の動作を見てみましょう.

プロセスを実行しています

私たちの生産は正常に運行しており、コンポーネントの1つを変更して、パラメータの1つで表示されるデフォルト値が異なるようにしたいです.

今、私たちはTenantId パラメータに値 ZZZ-999 を設定する、素晴らしい、私たちのローカルインスタンスの Visual Studio Code にあるコードを修正し、変更を GitHub にアップロードしよう.

変更がリポジトリにプッシュされたので、私たちの Jenkins インスタンスからパイプラインを実行できる。パイプラインの出力を見てみよう.

全てが正しい;変更を検知し、スクリプトを正常に実行した。

パラメータが変更されたかどうかを確認し、本番環境が正常に再起動したかどうかを確認しましょう.

これで新しいTenantIdが手に入りました!完全に、打って変わっての成功です!

結論と次のステップ.

お気づきかもしれませんが、IRISには継続的インテグレーションプロセスに参加するための技術的な制限はありません。あなたの日常的な運用に最適な適切なスクリプトが必要なだけです。

本記事では、ヘルスのためのIRISとの連続統合の小さな例を見ましたが、これはConfiguration Mergeなどの機能を使用してデプロイできる特定の設定に拡張できます.

試してみてください!