Skip to content

indentation fix(3) -- heredoc in tmp file #14

indentation fix(3) -- heredoc in tmp file

indentation fix(3) -- heredoc in tmp file #14

# ==============================================================================
# This workflow:
# 1. Checks out cdisc-rules-engine (the engine itself)
# 2. Checks out cdisc-open-rules (rules + test data) into ./open-rules/
# 3. Installs engine Python dependencies
# 4. Iterates every Published/ rule from cdisc-open-rules
# 5. Runs the engine against each test case
# 6. Compares output with committed results.csv baseline
# 7. Publishes a Markdown report to Job Summary and as an artifact
# ==============================================================================
name: Validate Published Rules
on:
push:
branches:
- main
- 798-test-against-published
workflow_dispatch:
inputs:
rules_ref:
description: 'Branch/tag/SHA of cdisc-open-rules to validate against'
required: false
default: 'main'
jobs:
validate-published-rules:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
# -----------------------------------------------------------------------
# 1. Checkout cdisc-rules-engine
# -----------------------------------------------------------------------
- name: Checkout cdisc-rules-engine
uses: actions/checkout@v6
with:
repository: cdisc-org/cdisc-rules-engine
path: engine
token: ${{ secrets.GITHUB_TOKEN }}
# -----------------------------------------------------------------------
# 2. Checkout cdisc-open-rules (rules + test data + helper scripts)
# -----------------------------------------------------------------------
- name: Checkout cdisc-open-rules
uses: actions/checkout@v6
with:
repository: cdisc-org/cdisc-open-rules
ref: ${{ inputs.rules_ref || 'rules_2' }}
path: open-rules
# If cdisc-open-rules is private, add a PAT secret:
# token: ${{ secrets.CDISC_OPEN_RULES_TOKEN }}
# -----------------------------------------------------------------------
# 2b. Debug — verify directory layout
# -----------------------------------------------------------------------
- name: Debug — list workspace layout
run: |
echo "=== Workspace root ==="
ls -la
echo "=== open-rules/ ==="
ls -la open-rules/ || echo "open-rules/ NOT FOUND"
echo "=== open-rules/Published/ (first 10) ==="
ls open-rules/Published/ 2>/dev/null | head -10 || echo "Published/ NOT FOUND"
echo "=== engine/ ==="
ls engine/ | head -10 || echo "engine/ NOT FOUND"
# -----------------------------------------------------------------------
# 3. Set up Python
# -----------------------------------------------------------------------
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: '3.12'
# -----------------------------------------------------------------------
# 4. Install engine dependencies
# -----------------------------------------------------------------------
- name: Install engine dependencies
run: |
python -m venv venv
./venv/bin/pip install --upgrade pip
./venv/bin/pip install -r engine/requirements.txt
# -----------------------------------------------------------------------
# 5. Run validation for every Published rule
# -----------------------------------------------------------------------
- name: Run validation for all Published rules
id: validate
continue-on-error: true
run: |
chmod +x open-rules/.github/scripts/run_validation.sh
# Write the JSON-line parser once; called once per test case in the loop below
cat > /tmp/parse_case.py << 'PYEOF'
import sys, json, shlex
d = json.load(sys.stdin)
for k, v in [
('CASE_RULE', d['rule']),
('CASE_TYPE', d['type']),
('CASE_NUM', str(d['num'])),
('EXEC_OK', '\u2705' if d['exec'] else '\u274c'),
('EXPECTED', str(d.get('expected', ''))),
('GOT', str(d.get('got', ''))),
('MATCH', '\u2705' if d.get('match') else '\u274c'),
('DIFF_FILE', str(d.get('diff', ''))),
('STDERR_FILE', str(d.get('stderr', ''))),
]:
print(k + '=' + shlex.quote(v))
PYEOF
PYTHON_CMD="$(pwd)/venv/bin/python"
ENGINE_DIR="$(pwd)/engine"
RULES_ROOT="$(pwd)/open-rules"
PUBLISHED_DIR="$RULES_ROOT/Published"
SCRIPTS_DIR="$RULES_ROOT/.github/scripts"
SUMMARY_TABLE="$(pwd)/summary_table.md"
DETAIL_REPORT="$(pwd)/detail_report.md"
OVERALL_EXIT=0
RULE_PASS=0
RULE_FAIL=0
mapfile -t RULE_DIRS < <(find "$PUBLISHED_DIR" -mindepth 1 -maxdepth 1 -type d | sort)
if [ ${#RULE_DIRS[@]} -eq 0 ]; then
echo "::warning::No rule directories found under Published/"
exit 0
fi
echo "Found ${#RULE_DIRS[@]} rule(s) under Published/"
# -- Initialise summary table
{
echo "# Published Rules Validation — Summary"
echo ""
echo "| Rule | Type | Number | Execution | Expected | Got | Match |"
echo "|------|------|--------|-----------|----------|-----|-------|"
} > "$SUMMARY_TABLE"
# -- Initialise detail report
{
echo "# Published Rules Validation — Failure Details"
echo ""
} > "$DETAIL_REPORT"
for RULE_DIR in "${RULE_DIRS[@]}"; do
RULE_ID=$(basename "$RULE_DIR")
RULE_YML=$(find "$RULE_DIR" -maxdepth 1 -name "*.yml" | head -1)
if [ -z "$RULE_YML" ]; then
echo "::warning::Skipping $RULE_ID — no .yml file found"
continue
fi
echo "========================================"
echo " Validating $RULE_ID"
echo "========================================"
RULE_EXIT=0
ENGINE_DIR_OVERRIDE="$ENGINE_DIR" \
bash "$SCRIPTS_DIR/run_validation.sh" \
"Published/$RULE_ID" \
"$PYTHON_CMD" \
"$RULES_ROOT" \
|| RULE_EXIT=$?
# -- Parse per-test-case results produced by run_validation.sh
CASE_RESULTS="$RULES_ROOT/case_results.jsonl"
RULE_ROW_FAILED=0
if [ -f "$CASE_RESULTS" ]; then
while IFS= read -r line; do
# Parse all fields in a single python3 call — script written once above
eval "$(echo "$line" | python3 /tmp/parse_case.py)"
echo "| $CASE_RULE | $CASE_TYPE | $CASE_NUM | $EXEC_OK | $EXPECTED | $GOT | $MATCH |" >> "$SUMMARY_TABLE"
# Collect detail only for failures
if [[ "$EXEC_OK" == "❌" || "$MATCH" == "❌" ]]; then
RULE_ROW_FAILED=1
{
echo "## $CASE_RULE — $CASE_TYPE / $CASE_NUM"
if [[ "$EXEC_OK" == "❌" ]]; then
echo "**Execution failed.**"
if [ -f "$STDERR_FILE" ]; then
echo '```'
cat "$STDERR_FILE"
echo '```'
fi
else
echo "**Expected:** $EXPECTED **Got:** $GOT"
if [ -n "$DIFF_FILE" ] && [ -f "$DIFF_FILE" ]; then
echo '```diff'
cat "$DIFF_FILE"
echo '```'
fi
fi
echo ""
} >> "$DETAIL_REPORT"
fi
done < "$CASE_RESULTS"
rm -f "$CASE_RESULTS"
else
# write a single aggregate row
EXEC_OK=$( [ $RULE_EXIT -eq 0 ] && echo "✅" || echo "❌" )
echo "| $RULE_ID | — | — | $EXEC_OK | — | — | — |" >> "$SUMMARY_TABLE"
if [ $RULE_EXIT -ne 0 ]; then
RULE_ROW_FAILED=1
# Append whatever markdown run_validation.sh produced
if [ -f "$RULES_ROOT/validation_report.md" ]; then
{
echo "## $RULE_ID"
cat "$RULES_ROOT/validation_report.md"
echo ""
} >> "$DETAIL_REPORT"
fi
fi
fi
rm -f "$RULES_ROOT/validation_report.md"
if [ $RULE_ROW_FAILED -eq 0 ] && [ $RULE_EXIT -eq 0 ]; then
RULE_PASS=$((RULE_PASS + 1))
echo " → $RULE_ID: PASSED"
else
RULE_FAIL=$((RULE_FAIL + 1))
OVERALL_EXIT=1
echo " → $RULE_ID: FAILED"
fi
done
# -- Insert totals line into summary table
TOTALS="**Total:** $((RULE_PASS + RULE_FAIL)) | ✅ Passed: $RULE_PASS | ❌ Failed: $RULE_FAIL"
sed -i "2s|^|$TOTALS\n\n|" "$SUMMARY_TABLE"
exit $OVERALL_EXIT
# -----------------------------------------------------------------------
# 6. Upload both reports + raw results as artifacts
# -----------------------------------------------------------------------
- name: Upload validation artifacts
if: always()
uses: actions/upload-artifact@v6
with:
name: published-rules-validation-${{ github.run_id }}
path: |
open-rules/Published/**/results/results.json
summary_table.md
detail_report.md
if-no-files-found: warn
# -----------------------------------------------------------------------
# 7. Write ONLY the summary table to GitHub Actions Job Summary
# -----------------------------------------------------------------------
- name: Write summary table to workflow summary
if: always()
run: |
[ -f summary_table.md ] && cat summary_table.md >> $GITHUB_STEP_SUMMARY || true
# -----------------------------------------------------------------------
# 8. Fail the job if any rule failed
# -----------------------------------------------------------------------
- name: Check overall status
if: steps.validate.outcome == 'failure'
run: |
echo "One or more published rules failed validation — see the artifacts for detail_report.md."
exit 1