Files
BD-Core-FHIR-IG/.gitea/workflows/ci-cd.yaml
jobayer 3297b88035
Some checks failed
FHIR IG CI/CD Pipeline with Version Persistence / build-ig (push) Successful in 6m58s
FHIR IG CI/CD Pipeline with Version Persistence / deploy (push) Failing after 8s
ci: enhance pipeline with version persistence and direct deployment
- Add version extraction from IG and tag validation for releases
- Update package-list.json and package-feed.xml automatically on releases
- Replace Docker-based deployment with direct file upload via SCP/SSH
- Add publication request configuration for FHIR registry
- Remove obsolete Dockerfile.serve as deployment strategy changed
2025-12-22 12:58:59 +06:00

371 lines
13 KiB
YAML

name: FHIR IG CI/CD Pipeline with Version Persistence
on:
push:
branches: [ main, develop ]
tags:
- 'v*.*.*' # Trigger on version tags like v0.3.0
pull_request:
branches: [ main ]
env:
REGISTRY: git.dghs.gov.bd
IMAGE_NAME: gitadmin/bd-core-fhir-ig
jobs:
build-ig:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Extract version from IG
id: version
run: |
# Extract version from ImplementationGuide resource
VERSION=$(grep -oP '<version value="\K[^"]+' input/bd.fhir.core.xml | head -1)
if [ -z "$VERSION" ]; then
echo "ERROR: Could not extract version from ImplementationGuide XML"
exit 1
fi
echo "Extracted version: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
# Determine if this is a release build (git tag) or dev build
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
BUILD_TYPE="release"
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
# Verify tag matches IG version
if [ "$TAG_VERSION" != "$VERSION" ]; then
echo "ERROR: Git tag version ($TAG_VERSION) doesn't match IG version ($VERSION)"
exit 1
fi
else
BUILD_TYPE="dev"
fi
echo "build_type=$BUILD_TYPE" >> $GITHUB_OUTPUT
echo "Build type: $BUILD_TYPE"
- name: Install Docker CLI
run: |
apt-get update
apt-get install -y docker.io
docker --version
- name: Build FHIR IG
run: |
echo "Building FHIR IG version ${{ steps.version.outputs.version }}..."
CONTAINER_ID=$(docker create \
hl7fhir/ig-publisher-base:latest \
/bin/bash -c "cp -r /home/publisher/ig /tmp/build && cd /tmp/build && _updatePublisher.sh -y && _genonce.sh")
echo "Container ID: $CONTAINER_ID"
docker cp $(pwd)/. $CONTAINER_ID:/home/publisher/ig/
docker start -a $CONTAINER_ID
EXIT_CODE=$?
# Copy outputs
echo "Copying outputs from container..."
docker cp $CONTAINER_ID:/tmp/build/output ./output || echo "Warning: No output directory"
docker cp $CONTAINER_ID:/tmp/build/fsh-generated ./fsh-generated || echo "No FSH generated"
docker cp $CONTAINER_ID:/tmp/build/input-cache ./input-cache || echo "No input-cache"
docker cp $CONTAINER_ID:/tmp/build/temp ./temp || echo "No temp directory"
if [ $EXIT_CODE -ne 0 ]; then
echo "Build failed, showing logs:"
docker logs $CONTAINER_ID
docker rm $CONTAINER_ID
exit 1
fi
docker rm $CONTAINER_ID
if [ ! -f "output/index.html" ]; then
echo "ERROR: Build failed - no index.html"
exit 1
fi
echo "✅ Build successful!"
- name: Update package-list.json and package-feed.xml for releases
if: steps.version.outputs.build_type == 'release'
run: |
VERSION="${{ steps.version.outputs.version }}"
DATE=$(date +%Y-%m-%d)
DATETIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# Update package-list.json and package-feed.xml
cat > update-registry-files.py << 'EOF'
import json
import sys
import xml.etree.ElementTree as ET
from datetime import datetime
version = sys.argv[1]
date = sys.argv[2]
datetime_iso = sys.argv[3]
# ========== Update package-list.json ==========
with open('package-list.json', 'r') as f:
pkg_list = json.load(f)
# Update current build path
for entry in pkg_list['list']:
if entry['version'] == 'current':
entry['path'] = 'https://fhir.dghs.gov.bd/core/'
break
# Check if this version already exists
version_exists = any(e['version'] == version for e in pkg_list['list'])
if not version_exists:
# Add new version entry
new_entry = {
"version": version,
"date": date,
"desc": f"Release {version}",
"path": f"https://fhir.dghs.gov.bd/core/{version}/",
"status": "trial-use",
"sequence": "STU 1"
}
# Insert after 'current' entry
pkg_list['list'].insert(1, new_entry)
else:
# Update existing entry
for entry in pkg_list['list']:
if entry['version'] == version:
entry['date'] = date
entry['path'] = f"https://fhir.dghs.gov.bd/core/{version}/"
break
with open('output/package-list.json', 'w') as f:
json.dump(pkg_list, f, indent=2)
print(f"✅ Updated package-list.json with version {version}")
# ========== Update package-feed.xml ==========
# Register namespaces
ET.register_namespace('', 'http://www.w3.org/2005/Atom')
# Parse existing feed
tree = ET.parse('package-feed.xml')
root = tree.getroot()
ns = {'atom': 'http://www.w3.org/2005/Atom'}
# Update feed updated timestamp
updated_elem = root.find('atom:updated', ns)
if updated_elem is not None:
updated_elem.text = datetime_iso
# Check if entry for this version already exists
entry_exists = False
for entry in root.findall('atom:entry', ns):
title = entry.find('atom:title', ns)
if title is not None and version in title.text:
entry_exists = True
# Update existing entry timestamp
entry_updated = entry.find('atom:updated', ns)
if entry_updated is not None:
entry_updated.text = datetime_iso
break
# If entry doesn't exist, create new one
if not entry_exists:
new_entry = ET.Element('{http://www.w3.org/2005/Atom}entry')
title = ET.SubElement(new_entry, '{http://www.w3.org/2005/Atom}title')
title.text = f"bd.fhir.core version {version}"
link = ET.SubElement(new_entry, '{http://www.w3.org/2005/Atom}link')
link.set('rel', 'alternate')
link.set('href', f"https://fhir.dghs.gov.bd/core/{version}/")
entry_id = ET.SubElement(new_entry, '{http://www.w3.org/2005/Atom}id')
entry_id.text = f"https://fhir.dghs.gov.bd/core/{version}/"
entry_updated = ET.SubElement(new_entry, '{http://www.w3.org/2005/Atom}updated')
entry_updated.text = datetime_iso
summary = ET.SubElement(new_entry, '{http://www.w3.org/2005/Atom}summary')
summary.text = f"Release {version} of Bangladesh Core FHIR Implementation Guide"
# Insert new entry at the beginning (after feed metadata)
# Find the position after the last feed-level element
insert_pos = 0
for i, child in enumerate(root):
if child.tag.endswith('entry'):
insert_pos = i
break
insert_pos = i + 1
root.insert(insert_pos, new_entry)
# Write updated feed
tree.write('output/package-feed.xml', encoding='utf-8', xml_declaration=True)
print(f"✅ Updated package-feed.xml with version {version}")
EOF
python3 update-registry-files.py "$VERSION" "$DATE" "$DATETIME"
# Copy updated files
cp output/package-list.json package-list.json
cp output/package-feed.xml package-feed.xml
echo "📋 Updated registry files (package-list.json and package-feed.xml)"
- name: Prepare deployment artifact
run: |
VERSION="${{ steps.version.outputs.version }}"
BUILD_TYPE="${{ steps.version.outputs.build_type }}"
# Create a tarball of the output
if [ "$BUILD_TYPE" == "release" ]; then
tar -czf ig-output.tar.gz -C output .
else
tar -czf ig-output.tar.gz -C output .
fi
echo "version=$VERSION" > deployment.env
echo "build_type=$BUILD_TYPE" >> deployment.env
echo "build_date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> deployment.env
ls -lh ig-output.tar.gz
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: ig-output
path: |
ig-output.tar.gz
deployment.env
package-list.json
package-feed.xml
retention-days: 30
deploy:
needs: build-ig
runs-on: ubuntu-latest
if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: ig-output
- name: Load deployment env
id: deploy_info
run: |
source deployment.env
echo "version=$version" >> $GITHUB_OUTPUT
echo "build_type=$build_type" >> $GITHUB_OUTPUT
echo "build_date=$build_date" >> $GITHUB_OUTPUT
echo "Deploying version: $version"
echo "Build type: $build_type"
- name: Deploy to server
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
password: ${{ secrets.DEPLOY_PASSWORD }}
port: ${{ secrets.DEPLOY_PORT || 22 }}
source: "ig-output.tar.gz,deployment.env,package-list.json,package-feed.xml"
target: "/tmp/fhir-ig-deploy/"
- name: Execute deployment on server
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
password: ${{ secrets.DEPLOY_PASSWORD }}
port: ${{ secrets.DEPLOY_PORT || 22 }}
script: |
set -e
# Load deployment info
source /tmp/fhir-ig-deploy/deployment.env
echo "=========================================="
echo "Deploying FHIR IG"
echo "Version: $version"
echo "Build Type: $build_type"
echo "Build Date: $build_date"
echo "=========================================="
# Create version directory structure
VERSIONS_DIR="/opt/fhir-ig/versions"
mkdir -p "$VERSIONS_DIR"
# Determine target directory
if [ "$build_type" == "release" ]; then
TARGET_DIR="$VERSIONS_DIR/$version"
echo "📦 Deploying release version to: $TARGET_DIR"
else
TARGET_DIR="$VERSIONS_DIR/dev"
echo "🔧 Deploying dev build to: $TARGET_DIR"
fi
# Create target directory
mkdir -p "$TARGET_DIR"
# Extract IG output
echo "Extracting IG output..."
tar -xzf /tmp/fhir-ig-deploy/ig-output.tar.gz -C "$TARGET_DIR"
# Copy package-list.json to root
cp /tmp/fhir-ig-deploy/package-list.json "$VERSIONS_DIR/package-list.json"
# Copy package-feed.xml to root
cp /tmp/fhir-ig-deploy/package-feed.xml "$VERSIONS_DIR/package-feed.xml"
# Update 'current' symlink for releases
if [ "$build_type" == "release" ]; then
echo "Updating 'current' symlink to point to $version"
rm -f "$VERSIONS_DIR/current"
ln -sf "$version" "$VERSIONS_DIR/current"
fi
# Ensure nginx container is running with correct config
cd /opt/fhir-ig
# Download deployment files if they don't exist
if [ ! -f "docker-compose.prod.yml" ]; then
echo "ERROR: docker-compose.prod.yml not found!"
echo "Please deploy the updated docker-compose.prod.yml and nginx.conf first"
exit 1
fi
# Restart nginx to pick up new content
docker compose -f docker-compose.prod.yml restart fhir-ig || \
docker compose -f docker-compose.prod.yml up -d
# Cleanup
rm -rf /tmp/fhir-ig-deploy
echo "=========================================="
echo "✅ Deployment completed successfully!"
echo "Version $version is now available at:"
if [ "$build_type" == "release" ]; then
echo " - https://fhir.dghs.gov.bd/core/$version/"
echo " - https://fhir.dghs.gov.bd/core/ (current)"
else
echo " - https://fhir.dghs.gov.bd/core/dev/"
fi
echo "=========================================="
# List all versions
echo "Available versions:"
ls -lh "$VERSIONS_DIR" | grep -v total