Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4813f63da5 | |||
| 04ef3b0b55 | |||
| 25f0017595 | |||
| a5e39b94d3 | |||
| 9968c28e5c | |||
| 7125b57aa2 | |||
| 958eba6c44 | |||
| fcb5002641 | |||
| b7c824b34a | |||
| e8cf5ab9be | |||
| c35bc8e8a4 | |||
| c2e7119335 | |||
| c6903044aa | |||
| aca893377c | |||
| ccf6fef643 | |||
| c80f2f3a40 | |||
| 804a7ff3d6 | |||
| db2f074cbe | |||
| 7731328402 | |||
| a5d41e88de | |||
| 5ca0ffdd86 | |||
| d82e428e24 | |||
| dc43651043 | |||
| 2fc782a082 | |||
| 2db03cd2cc | |||
| 323abf04dc | |||
| e3de38a794 | |||
| 9ed33227d3 | |||
| 8ddb62ab26 | |||
| c2be28e714 | |||
| dee47229d7 | |||
| a60c2c6c21 | |||
| b759890259 | |||
| c9cf4c5157 | |||
| 45505bd4b8 | |||
| 3e1f6979b5 | |||
| c39615ff85 | |||
| 06d3a6ef13 | |||
| 8c8b8f032c | |||
| 4d24e3f30c | |||
| 57aba6ddc6 | |||
| 665ba07e37 | |||
| 18f71a6a04 | |||
| 83ad838fc4 | |||
| 63ca3fa44f | |||
| fdca2f9c3b | |||
| 3b48bd79e2 | |||
| b620db17d5 | |||
| f2201f4da8 | |||
| b3cf356b32 | |||
| 7cb360b1d2 | |||
| 6beb9318fe | |||
| 423d1c271f | |||
| 53190dddd6 | |||
| 5205c06bab | |||
| b89620b4ed | |||
| c195390fe7 | |||
| e6cb213212 | |||
| 0bce070ae2 | |||
| 9bf4b2d457 | |||
| 68c748b06e |
@@ -2,9 +2,8 @@ name: FHIR IG CI/CD Pipeline with Version Persistence
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main, develop ]
|
|
||||||
tags:
|
tags:
|
||||||
- 'v*.*.*' # Trigger on version tags like v0.3.0
|
- 'v*.*.*'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
|
||||||
@@ -14,357 +13,616 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-ig:
|
build-ig:
|
||||||
runs-on: ubuntu-latest
|
runs-on: fhir-runner
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Extract version from IG
|
- name: Extract version from IG
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
# Extract version from ImplementationGuide resource
|
VERSION=$(grep -oP '<version value="\K[^"]+' input/bd.fhir.core.xml | head -1)
|
||||||
VERSION=$(grep -oP '<version value="\K[^"]+' input/bd.fhir.core.xml | head -1)
|
|
||||||
|
|
||||||
if [ -z "$VERSION" ]; then
|
if [ -z "$VERSION" ]; then
|
||||||
echo "ERROR: Could not extract version from ImplementationGuide XML"
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
BUILD_TYPE="dev"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "build_type=$BUILD_TYPE" >> $GITHUB_OUTPUT
|
echo "Extracted version: $VERSION"
|
||||||
echo "Build type: $BUILD_TYPE"
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Install Docker CLI
|
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
|
||||||
run: |
|
BUILD_TYPE="release"
|
||||||
apt-get update
|
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
|
||||||
apt-get install -y docker.io
|
|
||||||
docker --version
|
|
||||||
|
|
||||||
- name: Build FHIR IG
|
if [ "$TAG_VERSION" != "$VERSION" ]; then
|
||||||
run: |
|
echo "ERROR: Git tag version ($TAG_VERSION) doesn't match IG version ($VERSION)"
|
||||||
echo "Building FHIR IG version ${{ steps.version.outputs.version }}..."
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
BUILD_TYPE="dev"
|
||||||
|
fi
|
||||||
|
|
||||||
CONTAINER_ID=$(docker create \
|
echo "build_type=$BUILD_TYPE" >> $GITHUB_OUTPUT
|
||||||
hl7fhir/ig-publisher-base:latest \
|
echo "Build type: $BUILD_TYPE"
|
||||||
/bin/bash -c "cp -r /home/publisher/ig /tmp/build && cd /tmp/build && _updatePublisher.sh -y && _genonce.sh")
|
|
||||||
|
|
||||||
echo "Container ID: $CONTAINER_ID"
|
- name: Prepare package-list.json and history.xml for IG Publisher
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
BUILD_TYPE="${{ steps.version.outputs.build_type }}"
|
||||||
|
DATE=$(date +%Y-%m-%d)
|
||||||
|
|
||||||
docker cp $(pwd)/. $CONTAINER_ID:/home/publisher/ig/
|
export VERSION DATE BUILD_TYPE
|
||||||
docker start -a $CONTAINER_ID
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
# Copy outputs
|
echo "📋 Preparing package-list.json and history.xml for IG Publisher..."
|
||||||
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
|
if [ ! -f "package-list.json" ]; then
|
||||||
echo "Build failed, showing logs:"
|
echo "⚠️ package-list.json not found in repo root"
|
||||||
docker logs $CONTAINER_ID
|
echo "Creating initial package-list.json..."
|
||||||
docker rm $CONTAINER_ID
|
cat > package-list.json << 'PKGEOF'
|
||||||
exit 1
|
{
|
||||||
fi
|
"package-id": "bd.fhir.core",
|
||||||
|
"title": "Bangladesh Core FHIR Implementation Guide",
|
||||||
|
"canonical": "https://fhir.dghs.gov.bd/core",
|
||||||
|
"introduction": "The Bangladesh Core FHIR IG defines national base profiles, value sets, and extensions for health data interoperability.",
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"version": "current",
|
||||||
|
"desc": "Continuous Integration Build (latest in version control)",
|
||||||
|
"path": "https://fhir.dghs.gov.bd/core/",
|
||||||
|
"status": "ci-build",
|
||||||
|
"current": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
PKGEOF
|
||||||
|
fi
|
||||||
|
|
||||||
docker rm $CONTAINER_ID
|
python3 << 'PYEOF'
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
if [ ! -f "output/index.html" ]; then
|
version = os.environ.get('VERSION', '')
|
||||||
echo "ERROR: Build failed - no index.html"
|
date = os.environ.get('DATE', '')
|
||||||
exit 1
|
build_type = os.environ.get('BUILD_TYPE', '')
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✅ Build successful!"
|
with open('package-list.json', 'r', encoding='utf-8') as f:
|
||||||
|
pkg_list = json.load(f)
|
||||||
|
|
||||||
- name: Update package-list.json and package-feed.xml for releases
|
if 'list' not in pkg_list or not isinstance(pkg_list['list'], list):
|
||||||
if: steps.version.outputs.build_type == 'release'
|
print("ERROR: package-list.json does not contain a valid 'list' array")
|
||||||
run: |
|
sys.exit(1)
|
||||||
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
|
current_entries = [e for e in pkg_list['list'] if e.get('version') == 'current']
|
||||||
cat > update-registry-files.py << 'EOF'
|
if not current_entries:
|
||||||
import json
|
pkg_list['list'].insert(0, {
|
||||||
import sys
|
"version": "current",
|
||||||
import xml.etree.ElementTree as ET
|
"desc": "Continuous Integration Build (latest in version control)",
|
||||||
from datetime import datetime
|
"path": "https://fhir.dghs.gov.bd/core/",
|
||||||
|
"status": "ci-build",
|
||||||
|
"current": True
|
||||||
|
})
|
||||||
|
|
||||||
version = sys.argv[1]
|
if build_type == 'release':
|
||||||
date = sys.argv[2]
|
version_entry = None
|
||||||
datetime_iso = sys.argv[3]
|
for e in pkg_list['list']:
|
||||||
|
if e.get('version') == version:
|
||||||
|
version_entry = e
|
||||||
|
break
|
||||||
|
if version_entry is None:
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
# ========== Update package-list.json ==========
|
insert_index = 1
|
||||||
with open('package-list.json', 'r') as f:
|
for i, entry in enumerate(pkg_list['list']):
|
||||||
pkg_list = json.load(f)
|
if entry.get('version') == 'current':
|
||||||
|
insert_index = i + 1
|
||||||
|
break
|
||||||
|
|
||||||
# Update current build path
|
pkg_list['list'].insert(insert_index, new_entry)
|
||||||
for entry in pkg_list['list']:
|
print(f"✅ Added version {version} to package-list.json")
|
||||||
if entry['version'] == 'current':
|
else:
|
||||||
entry['path'] = 'https://fhir.dghs.gov.bd/core/'
|
print(f"ℹ️ Version {version} already exists in package-list.json")
|
||||||
break
|
else:
|
||||||
|
print("ℹ️ Dev build - using existing package-list.json without release modification")
|
||||||
|
|
||||||
# Check if this version already exists
|
with open('package-list.json', 'w', encoding='utf-8') as f:
|
||||||
version_exists = any(e['version'] == version for e in pkg_list['list'])
|
json.dump(pkg_list, f, indent=2, ensure_ascii=False)
|
||||||
|
PYEOF
|
||||||
|
|
||||||
if not version_exists:
|
echo "🔍 Validating package-list.json..."
|
||||||
# Add new version entry
|
python3 -m json.tool package-list.json > /dev/null && echo "✅ Valid JSON" || (echo "❌ Invalid JSON!" && exit 1)
|
||||||
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:
|
echo "📂 Ensuring package-list.json is in required locations..."
|
||||||
json.dump(pkg_list, f, indent=2)
|
mkdir -p input
|
||||||
|
cp package-list.json input/package-list.json
|
||||||
|
|
||||||
print(f"✅ Updated package-list.json with version {version}")
|
echo "📝 Generating static history.xml from package-list.json..."
|
||||||
|
mkdir -p input/pagecontent
|
||||||
|
|
||||||
# ========== Update package-feed.xml ==========
|
python3 << 'PYEOF'
|
||||||
# Register namespaces
|
import json
|
||||||
ET.register_namespace('', 'http://www.w3.org/2005/Atom')
|
import os
|
||||||
|
from html import escape
|
||||||
|
|
||||||
# Parse existing feed
|
os.makedirs('input/pagecontent', exist_ok=True)
|
||||||
tree = ET.parse('package-feed.xml')
|
|
||||||
root = tree.getroot()
|
|
||||||
ns = {'atom': 'http://www.w3.org/2005/Atom'}
|
|
||||||
|
|
||||||
# Update feed updated timestamp
|
with open('package-list.json', 'r', encoding='utf-8') as f:
|
||||||
updated_elem = root.find('atom:updated', ns)
|
pkg_list = json.load(f)
|
||||||
if updated_elem is not None:
|
|
||||||
updated_elem.text = datetime_iso
|
|
||||||
|
|
||||||
# Check if entry for this version already exists
|
xml = '''<?xml version="1.0" encoding="UTF-8"?>
|
||||||
entry_exists = False
|
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||||
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
|
<p>This page provides the version history for the Bangladesh Core FHIR Implementation Guide.</p>
|
||||||
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')
|
<p>For a machine-readable version history see <a href="package-list.json">package-list.json</a>.</p>
|
||||||
title.text = f"bd.fhir.core version {version}"
|
|
||||||
|
|
||||||
link = ET.SubElement(new_entry, '{http://www.w3.org/2005/Atom}link')
|
<p><b>Published Versions</b></p>
|
||||||
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')
|
<table class="grid table table-striped table-bordered table-hover">
|
||||||
entry_id.text = f"https://fhir.dghs.gov.bd/core/{version}/"
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Version</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
'''
|
||||||
|
|
||||||
entry_updated = ET.SubElement(new_entry, '{http://www.w3.org/2005/Atom}updated')
|
def version_key(v):
|
||||||
entry_updated.text = datetime_iso
|
try:
|
||||||
|
return tuple(int(x) for x in v.split('.'))
|
||||||
|
except:
|
||||||
|
return (0,)
|
||||||
|
|
||||||
summary = ET.SubElement(new_entry, '{http://www.w3.org/2005/Atom}summary')
|
published = [
|
||||||
summary.text = f"Release {version} of Bangladesh Core FHIR Implementation Guide"
|
e for e in pkg_list['list']
|
||||||
|
if e.get('version') and e.get('version') != "current"
|
||||||
|
]
|
||||||
|
|
||||||
# Insert new entry at the beginning (after feed metadata)
|
# Sort newest version first
|
||||||
# Find the position after the last feed-level element
|
published.sort(
|
||||||
insert_pos = 0
|
key=lambda e: version_key(e.get("version", "0.0.0")),
|
||||||
for i, child in enumerate(root):
|
reverse=True
|
||||||
if child.tag.endswith('entry'):
|
)
|
||||||
insert_pos = i
|
|
||||||
break
|
|
||||||
insert_pos = i + 1
|
|
||||||
|
|
||||||
root.insert(insert_pos, new_entry)
|
published_found = False
|
||||||
|
first_row = True
|
||||||
|
|
||||||
# Write updated feed
|
for entry in published:
|
||||||
tree.write('output/package-feed.xml', encoding='utf-8', xml_declaration=True)
|
published_found = True
|
||||||
print(f"✅ Updated package-feed.xml with version {version}")
|
|
||||||
|
|
||||||
EOF
|
version = escape(entry.get('version', 'Unknown'))
|
||||||
|
date = escape(entry.get('date', 'N/A'))
|
||||||
|
desc = escape(entry.get('desc', ''))
|
||||||
|
path = escape(entry.get('path', '#'))
|
||||||
|
|
||||||
python3 update-registry-files.py "$VERSION" "$DATE" "$DATETIME"
|
status_val = entry.get('status', 'unknown')
|
||||||
|
|
||||||
# Copy updated files
|
if status_val == "trial-use":
|
||||||
cp output/package-list.json package-list.json
|
status = '<span class="badge bg-info">Trial Use</span>'
|
||||||
cp output/package-feed.xml package-feed.xml
|
elif status_val == "normative":
|
||||||
|
status = '<span class="badge bg-success">Normative</span>'
|
||||||
|
else:
|
||||||
|
status = f'<span class="badge bg-secondary">{escape(status_val)}</span>'
|
||||||
|
|
||||||
echo "📋 Updated registry files (package-list.json and package-feed.xml)"
|
badge = '<span class="badge bg-success">Latest</span> ' if first_row else ''
|
||||||
|
|
||||||
- name: Prepare deployment artifact
|
xml += f'''
|
||||||
run: |
|
<tr>
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
<td><a href="{path}">{badge}{version}</a></td>
|
||||||
BUILD_TYPE="${{ steps.version.outputs.build_type }}"
|
<td>{date}</td>
|
||||||
|
<td>{status}</td>
|
||||||
|
<td>{desc}</td>
|
||||||
|
</tr>
|
||||||
|
'''
|
||||||
|
|
||||||
|
first_row = False
|
||||||
|
|
||||||
|
if not published_found:
|
||||||
|
xml += '''
|
||||||
|
<tr>
|
||||||
|
<td colspan="4">No published versions available yet.</td>
|
||||||
|
</tr>
|
||||||
|
'''
|
||||||
|
|
||||||
|
xml += '''
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="lead"><b>Continuous Integration Build</b></p>
|
||||||
|
'''
|
||||||
|
|
||||||
|
current_entry = None
|
||||||
|
for entry in pkg_list['list']:
|
||||||
|
if entry.get('version') == 'current':
|
||||||
|
current_entry = entry
|
||||||
|
break
|
||||||
|
|
||||||
|
if current_entry:
|
||||||
|
path = escape(current_entry.get('path', pkg_list.get('canonical', '') + '/'))
|
||||||
|
xml += f'''
|
||||||
|
<p>The latest development build is available at:
|
||||||
|
<a href="{path}">{path}</a></p>
|
||||||
|
'''
|
||||||
|
else:
|
||||||
|
xml += '''
|
||||||
|
<p><i>No CI build entry found in package-list.json.</i></p>
|
||||||
|
'''
|
||||||
|
|
||||||
|
xml += '''
|
||||||
|
</div>
|
||||||
|
'''
|
||||||
|
|
||||||
|
with open('input/pagecontent/history.xml', 'w', encoding='utf-8') as f:
|
||||||
|
f.write(xml)
|
||||||
|
|
||||||
|
print("✅ Generated static history.xml")
|
||||||
|
print(f" File location: {os.path.abspath('input/pagecontent/history.xml')}")
|
||||||
|
print(f" File size: {os.path.getsize('input/pagecontent/history.xml')} bytes")
|
||||||
|
PYEOF
|
||||||
|
|
||||||
|
if [ -f "input/pagecontent/history.xml" ]; then
|
||||||
|
echo "✅ Verified: history.xml exists"
|
||||||
|
echo " First 20 lines:"
|
||||||
|
head -20 input/pagecontent/history.xml
|
||||||
|
else
|
||||||
|
echo "❌ ERROR: history.xml was not created!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Pre-build preparation complete:"
|
||||||
|
echo " - Root: $(pwd)/package-list.json"
|
||||||
|
echo " - Input: $(pwd)/input/package-list.json"
|
||||||
|
echo " - History: $(pwd)/input/pagecontent/history.xml"
|
||||||
|
echo "==============================="
|
||||||
|
echo "PACKAGE LIST USED FOR BUILD:"
|
||||||
|
cat package-list.json
|
||||||
|
echo "-------------------------------"
|
||||||
|
echo "INPUT COPY:"
|
||||||
|
cat input/package-list.json
|
||||||
|
echo "==============================="
|
||||||
|
|
||||||
|
- name: Emergency Disk Cleanup
|
||||||
|
run: |
|
||||||
|
echo "Disk usage before:"
|
||||||
|
df -h
|
||||||
|
|
||||||
|
echo "Clearing tool cache..."
|
||||||
|
rm -rf /opt/hostedtoolcache/* || true
|
||||||
|
|
||||||
|
rm -rf /usr/share/dotnet || true
|
||||||
|
rm -rf /usr/local/lib/android || true
|
||||||
|
rm -rf /opt/ghc || true
|
||||||
|
rm -rf ~/.fhir/packages || true
|
||||||
|
|
||||||
|
echo "Disk usage after:"
|
||||||
|
df -h
|
||||||
|
|
||||||
|
- name: Install Docker CLI
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y docker.io
|
||||||
|
docker --version
|
||||||
|
|
||||||
|
- name: Preload previous IG package for comparison
|
||||||
|
run: |
|
||||||
|
echo "Detecting previous version..."
|
||||||
|
|
||||||
|
PREV_VERSION=$(python3 <<'PY'
|
||||||
|
import json
|
||||||
|
with open("package-list.json") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
versions = [v["version"] for v in data["list"] if v["version"] != "current"]
|
||||||
|
print(versions[0] if versions else "")
|
||||||
|
PY
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ -z "$PREV_VERSION" ]; then
|
||||||
|
echo "No previous version found. Skipping preload."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Previous version detected: $PREV_VERSION"
|
||||||
|
|
||||||
|
mkdir -p previous-packages
|
||||||
|
TMPDIR=$(mktemp -d)
|
||||||
|
|
||||||
|
URL="https://fhir.dghs.gov.bd/core/$PREV_VERSION/package.tgz"
|
||||||
|
|
||||||
|
echo "Downloading $URL"
|
||||||
|
curl -L "$URL" -o "$TMPDIR/package.tgz"
|
||||||
|
|
||||||
|
mkdir -p "previous-packages/bd.fhir.core#$PREV_VERSION"
|
||||||
|
tar -xzf "$TMPDIR/package.tgz" -C "previous-packages/bd.fhir.core#$PREV_VERSION"
|
||||||
|
|
||||||
|
echo "Previous package cached:"
|
||||||
|
ls previous-packages
|
||||||
|
|
||||||
|
- name: Build FHIR IG
|
||||||
|
run: |
|
||||||
|
echo "Building FHIR IG version ${{ steps.version.outputs.version }}..."
|
||||||
|
|
||||||
|
CONTAINER_ID=$(docker create \
|
||||||
|
-v $(pwd)/previous-packages:/previous-packages \
|
||||||
|
hl7fhir/ig-publisher-base:latest \
|
||||||
|
/bin/bash -c "
|
||||||
|
|
||||||
|
mkdir -p /tmp/build
|
||||||
|
cp -r /home/publisher/ig /tmp/build/ig
|
||||||
|
|
||||||
|
cd /tmp/build/ig
|
||||||
|
|
||||||
|
rm -f package-list.json
|
||||||
|
|
||||||
|
_updatePublisher.sh -y
|
||||||
|
_genonce.sh
|
||||||
|
")
|
||||||
|
|
||||||
|
echo "Container ID: $CONTAINER_ID"
|
||||||
|
|
||||||
|
docker cp "$(pwd)/." "$CONTAINER_ID:/home/publisher/ig/"
|
||||||
|
echo "Mounted FHIR packages:"
|
||||||
|
ls -R previous-packages || echo "No previous packages directory"
|
||||||
|
docker start -a "$CONTAINER_ID"
|
||||||
|
EXIT_CODE=$?
|
||||||
|
|
||||||
|
echo "Copying outputs from container..."
|
||||||
|
docker cp "$CONTAINER_ID:/tmp/build/ig/output" ./output || echo "Warning: No output directory"
|
||||||
|
docker cp "$CONTAINER_ID:/tmp/build/ig/fsh-generated" ./fsh-generated || echo "No FSH generated"
|
||||||
|
docker cp "$CONTAINER_ID:/tmp/build/ig/input-cache" ./input-cache || echo "No input-cache"
|
||||||
|
docker cp "$CONTAINER_ID:/tmp/build/ig/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 ""
|
||||||
|
echo "🔍 Checking for history.html..."
|
||||||
|
if [ -f "output/history.html" ]; then
|
||||||
|
echo "✅ history.html generated successfully!"
|
||||||
|
echo "📄 history.html size: $(ls -lh output/history.html | awk '{print $5}')"
|
||||||
|
else
|
||||||
|
echo "⚠️ WARNING: history.html was NOT generated"
|
||||||
|
echo "This might indicate an issue with the template or history.xml/package-list.json"
|
||||||
|
fi
|
||||||
|
echo "================================"
|
||||||
|
echo "IG Publisher comparison log:"
|
||||||
|
cat output/qa.compare.txt || echo "qa.compare.txt not found"
|
||||||
|
echo "================================"
|
||||||
|
echo "✅ Build successful!"
|
||||||
|
|
||||||
|
- name: Update package-feed.xml for releases
|
||||||
|
if: steps.version.outputs.build_type == 'release'
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
DATETIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||||
|
|
||||||
|
cat > update-feed.py << 'EOF'
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
version = sys.argv[1]
|
||||||
|
datetime_iso = sys.argv[2]
|
||||||
|
|
||||||
|
ET.register_namespace('', 'http://www.w3.org/2005/Atom')
|
||||||
|
|
||||||
|
tree = ET.parse('package-feed.xml')
|
||||||
|
root = tree.getroot()
|
||||||
|
ns = {'atom': 'http://www.w3.org/2005/Atom'}
|
||||||
|
|
||||||
|
updated_elem = root.find('atom:updated', ns)
|
||||||
|
if updated_elem is not None:
|
||||||
|
updated_elem.text = datetime_iso
|
||||||
|
|
||||||
|
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 or ''):
|
||||||
|
entry_exists = True
|
||||||
|
entry_updated = entry.find('atom:updated', ns)
|
||||||
|
if entry_updated is not None:
|
||||||
|
entry_updated.text = datetime_iso
|
||||||
|
break
|
||||||
|
|
||||||
|
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_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)
|
||||||
|
|
||||||
|
tree.write('output/package-feed.xml', encoding='utf-8', xml_declaration=True)
|
||||||
|
print("✅ Updated package-feed.xml")
|
||||||
|
EOF
|
||||||
|
|
||||||
|
python3 update-feed.py "$VERSION" "$DATETIME"
|
||||||
|
cp package-list.json output/package-list.json
|
||||||
|
|
||||||
|
echo "📋 Updated registry files"
|
||||||
|
|
||||||
|
- 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 .
|
tar -czf ig-output.tar.gz -C output .
|
||||||
else
|
|
||||||
tar -czf ig-output.tar.gz -C output .
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "version=$VERSION" > deployment.env
|
echo "version=$VERSION" > deployment.env
|
||||||
echo "build_type=$BUILD_TYPE" >> deployment.env
|
echo "build_type=$BUILD_TYPE" >> deployment.env
|
||||||
echo "build_date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> deployment.env
|
echo "build_date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> deployment.env
|
||||||
|
|
||||||
ls -lh ig-output.tar.gz
|
echo "📦 Output contents:"
|
||||||
|
ls -lh output/ | grep -E "(history\.html|package-list\.json|package-feed\.xml|index\.html)" || echo "Some files may be missing"
|
||||||
|
|
||||||
- name: Upload artifact
|
ls -lh ig-output.tar.gz
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
- name: Upload artifact
|
||||||
name: ig-output
|
uses: actions/upload-artifact@v3
|
||||||
path: |
|
with:
|
||||||
ig-output.tar.gz
|
name: ig-output
|
||||||
deployment.env
|
path: |
|
||||||
package-list.json
|
ig-output.tar.gz
|
||||||
package-feed.xml
|
deployment.env
|
||||||
retention-days: 30
|
package-list.json
|
||||||
|
package-feed.xml
|
||||||
|
retention-days: 30
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
needs: build-ig
|
needs: build-ig
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download artifact
|
- name: Download artifact
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: ig-output
|
name: ig-output
|
||||||
|
|
||||||
- name: Load deployment env
|
- name: Load deployment env
|
||||||
id: deploy_info
|
id: deploy_info
|
||||||
run: |
|
run: |
|
||||||
source deployment.env
|
source deployment.env
|
||||||
echo "version=$version" >> $GITHUB_OUTPUT
|
echo "version=$version" >> $GITHUB_OUTPUT
|
||||||
echo "build_type=$build_type" >> $GITHUB_OUTPUT
|
echo "build_type=$build_type" >> $GITHUB_OUTPUT
|
||||||
echo "build_date=$build_date" >> $GITHUB_OUTPUT
|
echo "build_date=$build_date" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
echo "Deploying version: $version"
|
echo "Deploying version: $version"
|
||||||
echo "Build type: $build_type"
|
echo "Build type: $build_type"
|
||||||
|
|
||||||
- name: Deploy to server
|
- name: Deploy to server
|
||||||
uses: appleboy/scp-action@v0.1.7
|
uses: appleboy/scp-action@v0.1.7
|
||||||
with:
|
with:
|
||||||
host: ${{ secrets.DEPLOY_HOST }}
|
host: ${{ secrets.DEPLOY_HOST }}
|
||||||
username: ${{ secrets.DEPLOY_USER }}
|
username: ${{ secrets.DEPLOY_USER }}
|
||||||
password: ${{ secrets.DEPLOY_PASSWORD }}
|
password: ${{ secrets.DEPLOY_PASSWORD }}
|
||||||
port: ${{ secrets.DEPLOY_PORT || 22 }}
|
port: ${{ secrets.DEPLOY_PORT || 22 }}
|
||||||
source: "ig-output.tar.gz,deployment.env,package-list.json,package-feed.xml"
|
source: "ig-output.tar.gz,deployment.env,package-list.json,package-feed.xml"
|
||||||
target: "/tmp/fhir-ig-deploy/"
|
target: "/tmp/fhir-ig-deploy/"
|
||||||
|
|
||||||
- name: Execute deployment on server
|
- name: Execute deployment on server
|
||||||
uses: appleboy/ssh-action@v1.0.3
|
uses: appleboy/ssh-action@v1.0.3
|
||||||
with:
|
with:
|
||||||
host: ${{ secrets.DEPLOY_HOST }}
|
host: ${{ secrets.DEPLOY_HOST }}
|
||||||
username: ${{ secrets.DEPLOY_USER }}
|
username: ${{ secrets.DEPLOY_USER }}
|
||||||
password: ${{ secrets.DEPLOY_PASSWORD }}
|
password: ${{ secrets.DEPLOY_PASSWORD }}
|
||||||
port: ${{ secrets.DEPLOY_PORT || 22 }}
|
port: ${{ secrets.DEPLOY_PORT || 22 }}
|
||||||
script: |
|
script: |
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Load deployment info
|
source /tmp/fhir-ig-deploy/deployment.env
|
||||||
source /tmp/fhir-ig-deploy/deployment.env
|
|
||||||
|
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "Deploying FHIR IG"
|
echo "Deploying FHIR IG"
|
||||||
echo "Version: $version"
|
echo "Version: $version"
|
||||||
echo "Build Type: $build_type"
|
echo "Build Type: $build_type"
|
||||||
echo "Build Date: $build_date"
|
echo "Build Date: $build_date"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
|
|
||||||
# Create version directory structure
|
VERSIONS_DIR="/opt/fhir-ig/versions"
|
||||||
VERSIONS_DIR="/opt/fhir-ig/versions"
|
mkdir -p "$VERSIONS_DIR"
|
||||||
mkdir -p "$VERSIONS_DIR"
|
|
||||||
|
|
||||||
# Determine target directory
|
if [ "$build_type" = "release" ]; then
|
||||||
if [ "$build_type" == "release" ]; then
|
TARGET_DIR="$VERSIONS_DIR/$version"
|
||||||
TARGET_DIR="$VERSIONS_DIR/$version"
|
echo "📦 Deploying release version to: $TARGET_DIR"
|
||||||
echo "📦 Deploying release version to: $TARGET_DIR"
|
else
|
||||||
else
|
TARGET_DIR="$VERSIONS_DIR/dev"
|
||||||
TARGET_DIR="$VERSIONS_DIR/dev"
|
echo "🔧 Deploying dev build to: $TARGET_DIR"
|
||||||
echo "🔧 Deploying dev build to: $TARGET_DIR"
|
mkdir -p "$TARGET_DIR"
|
||||||
fi
|
echo "Cleaning old dev files..."
|
||||||
|
rm -rf "$TARGET_DIR"/*
|
||||||
|
fi
|
||||||
|
|
||||||
# Create target directory
|
mkdir -p "$TARGET_DIR"
|
||||||
mkdir -p "$TARGET_DIR"
|
|
||||||
|
|
||||||
# Extract IG output
|
echo "Extracting IG output..."
|
||||||
echo "Extracting IG output..."
|
tar -xzf /tmp/fhir-ig-deploy/ig-output.tar.gz -C "$TARGET_DIR"
|
||||||
tar -xzf /tmp/fhir-ig-deploy/ig-output.tar.gz -C "$TARGET_DIR"
|
|
||||||
|
|
||||||
# Copy package-list.json to root
|
if [ -f "$TARGET_DIR/history.html" ]; then
|
||||||
cp /tmp/fhir-ig-deploy/package-list.json "$VERSIONS_DIR/package-list.json"
|
echo "✅ history.html deployed successfully"
|
||||||
|
else
|
||||||
|
echo "⚠️ WARNING: history.html not found in deployment"
|
||||||
|
fi
|
||||||
|
|
||||||
# Copy package-feed.xml to root
|
cp "$TARGET_DIR/package-list.json" "$VERSIONS_DIR/package-list.json"
|
||||||
cp /tmp/fhir-ig-deploy/package-feed.xml "$VERSIONS_DIR/package-feed.xml"
|
cp "$TARGET_DIR/package-feed.xml" "$VERSIONS_DIR/package-feed.xml"
|
||||||
|
|
||||||
# Update 'current' symlink for releases
|
cp "$TARGET_DIR/package-list.json" "/opt/fhir-ig/package-list.json"
|
||||||
if [ "$build_type" == "release" ]; then
|
cp "$TARGET_DIR/package-feed.xml" "/opt/fhir-ig/package-feed.xml"
|
||||||
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
|
if [ "$build_type" = "release" ]; then
|
||||||
cd /opt/fhir-ig
|
echo "Updating 'current' symlink to point to $version"
|
||||||
|
rm -f "$VERSIONS_DIR/current"
|
||||||
|
ln -sf "$version" "$VERSIONS_DIR/current"
|
||||||
|
fi
|
||||||
|
|
||||||
# Download deployment files if they don't exist
|
cd /opt/fhir-ig
|
||||||
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
|
if [ ! -f "docker-compose.prod.yml" ]; then
|
||||||
docker compose -f docker-compose.prod.yml restart fhir-ig || \
|
echo "ERROR: docker-compose.prod.yml not found!"
|
||||||
docker compose -f docker-compose.prod.yml up -d
|
echo "Please deploy the updated docker-compose.prod.yml and nginx.conf first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Cleanup
|
docker compose -f docker-compose.prod.yml up -d --force-recreate fhir-ig
|
||||||
rm -rf /tmp/fhir-ig-deploy
|
|
||||||
|
|
||||||
echo "=========================================="
|
rm -rf /tmp/fhir-ig-deploy
|
||||||
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 "=========================================="
|
||||||
echo "Available versions:"
|
echo "✅ Deployment completed successfully!"
|
||||||
ls -lh "$VERSIONS_DIR" | grep -v total
|
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/$version/history.html"
|
||||||
|
echo " - https://fhir.dghs.gov.bd/core/ (current)"
|
||||||
|
else
|
||||||
|
echo " - https://fhir.dghs.gov.bd/core/dev/"
|
||||||
|
fi
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
echo "Available versions:"
|
||||||
|
ls -lh "$VERSIONS_DIR" | grep -v total
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</extension>-->
|
</extension>-->
|
||||||
<url value="https://fhir.dghs.gov.bd/core/ImplementationGuide/bd.fhir.core"/>
|
<url value="https://fhir.dghs.gov.bd/core/ImplementationGuide/bd.fhir.core"/>
|
||||||
<!-- This version will propagate to all artifacts unless the "propagate-version" extension is overridden -->
|
<!-- This version will propagate to all artifacts unless the "propagate-version" extension is overridden -->
|
||||||
<version value="0.2.4"/>
|
<version value="0.2.5"/>
|
||||||
<name value="BangladeshCoreFHIRIG"/>
|
<name value="BangladeshCoreFHIRIG"/>
|
||||||
<title value="Bangladesh Core FHIR Implementation Guide"/>
|
<title value="Bangladesh Core FHIR Implementation Guide"/>
|
||||||
<status value="active"/>
|
<status value="active"/>
|
||||||
@@ -102,6 +102,11 @@
|
|||||||
<title value="IG Change History"/>
|
<title value="IG Change History"/>
|
||||||
<generation value="html"/>
|
<generation value="html"/>
|
||||||
</page>
|
</page>
|
||||||
|
<page>
|
||||||
|
<nameUrl value="history.html"/>
|
||||||
|
<title value="Version History"/>
|
||||||
|
<generation value="html"/>
|
||||||
|
</page>
|
||||||
</page>
|
</page>
|
||||||
<!-- copyright year is a mandatory parameter -->
|
<!-- copyright year is a mandatory parameter -->
|
||||||
<parameter>
|
<parameter>
|
||||||
|
|||||||
@@ -11,6 +11,14 @@
|
|||||||
"status": "ci-build",
|
"status": "ci-build",
|
||||||
"current": true
|
"current": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"version": "0.2.4",
|
||||||
|
"date": "2025-10-06",
|
||||||
|
"desc": "Second draft release of the Bangladesh Core FHIR IG",
|
||||||
|
"path": "https://fhir.dghs.gov.bd/core/0.2.4/",
|
||||||
|
"status": "trial-use",
|
||||||
|
"sequence": "STU 1"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "0.2.3",
|
"version": "0.2.3",
|
||||||
"date": "2025-10-06",
|
"date": "2025-10-06",
|
||||||
|
|||||||
@@ -11,6 +11,14 @@
|
|||||||
"status": "ci-build",
|
"status": "ci-build",
|
||||||
"current": true
|
"current": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"version": "0.2.4",
|
||||||
|
"date": "2025-10-06",
|
||||||
|
"desc": "Second draft release of the Bangladesh Core FHIR IG",
|
||||||
|
"path": "https://fhir.dghs.gov.bd/core/0.2.4/",
|
||||||
|
"status": "trial-use",
|
||||||
|
"sequence": "STU 1"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "0.2.3",
|
"version": "0.2.3",
|
||||||
"date": "2025-10-06",
|
"date": "2025-10-06",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ description: >
|
|||||||
This Implementation Guide defines the Bangladesh Core FHIR profiles,
|
This Implementation Guide defines the Bangladesh Core FHIR profiles,
|
||||||
value sets, code systems, and implementation rules for national digital health systems.
|
value sets, code systems, and implementation rules for national digital health systems.
|
||||||
status: draft
|
status: draft
|
||||||
version: 0.2.4
|
version: 0.2.5
|
||||||
fhirVersion: 4.0.1
|
fhirVersion: 4.0.1
|
||||||
copyrightYear: 2025+
|
copyrightYear: 2025+
|
||||||
releaseLabel: CI Build
|
releaseLabel: CI Build
|
||||||
|
|||||||
Reference in New Issue
Block a user