Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3e5ca84
feat: add Mermaid workflow diagram generation and GitHub integration …
johnrwatson Jan 30, 2026
75805d0
remove lint and format check from integration test workflow
johnrwatson Jan 30, 2026
4a6353d
fix GitHub Actions expression syntax and improve workflow naming
johnrwatson Jan 30, 2026
f62ac59
fix: resolve type error in Mermaid model colorScheme default
johnrwatson Jan 30, 2026
68facac
fix: remove invalid --models-dir option from repo init
johnrwatson Jan 30, 2026
5b0b279
fix: correct JSON parsing and YAML formatting in integration workflow
johnrwatson Jan 30, 2026
0d25fab
fix: correct YAML syntax errors in integration workflow
johnrwatson Jan 30, 2026
6d9e12e
feat: add GitHub Actions workflow validation
johnrwatson Jan 30, 2026
0b627d8
fix: resolve YAML syntax errors by replacing heredocs with printf
johnrwatson Jan 30, 2026
10cbf15
fix: resolve YAML heredoc syntax error on line 130
johnrwatson Jan 30, 2026
58593ef
fix: escape GitHub Actions expressions in workflow validation
johnrwatson Jan 30, 2026
79c5184
fix: resolve all GitHub Actions workflow validation errors
johnrwatson Jan 30, 2026
5a61aa1
fix: add missing ref fields to workflow dependsOn conditions
johnrwatson Jan 30, 2026
45280dc
fix: correct swamp model expression paths for cross-model references
johnrwatson Jan 30, 2026
a60a600
fix: correct error handling test logic for failing models
johnrwatson Jan 30, 2026
557c73a
chore: ignore test-repo directory
johnrwatson Jan 30, 2026
2809cf5
chore: rename workflow to System Test
johnrwatson Jan 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 236 additions & 0 deletions .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
name: Swamp Integration Tests

on:
pull_request:
branches: [main]
types: [opened, synchronize]

permissions:
contents: read

jobs:
integration-test:
name: System Test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x

- name: Compile swamp binary
run: deno run compile

- name: Verify swamp binary works
run: |
./swamp --version
./swamp --help

- name: Create test repository structure
run: |
mkdir -p test-repo/{inputs/keeb/shell,inputs/mermaid/workflow-diagram,workflows,resources}
cd test-repo

# Initialize as swamp repo
../swamp repo init

- name: Create test models with shell commands
run: |
cd test-repo

# Model 1: Download a sample file
../swamp model create keeb/shell download-model --json > /tmp/download.json
DOWNLOAD_ID=$(cat /tmp/download.json | jq -r '.id')
# Edit the generated file to add our attributes
printf 'id: %s\nname: download-model\nversion: 1\ntags: {}\nattributes:\n run: "curl -s https://httpbin.org/json > sample.json && cat sample.json"\n workingDir: "/tmp"\n' "${DOWNLOAD_ID}" > "inputs/keeb/shell/${DOWNLOAD_ID}.yaml"

# Model 2: Process the downloaded file
../swamp model create keeb/shell process-model --json > /tmp/process.json
PROCESS_ID=$(cat /tmp/process.json | jq -r '.id')
printf 'id: %s\nname: process-model\nversion: 1\ntags: {}\nattributes:\n run: "wc -l /tmp/sample.json | cut -d'\''$'\'' -f1"\n workingDir: "/tmp"\n' "${PROCESS_ID}" > "inputs/keeb/shell/${PROCESS_ID}.yaml"

# Model 3: Create summary using self-reference
../swamp model create keeb/shell summary-model --json > /tmp/summary.json
SUMMARY_ID=$(cat /tmp/summary.json | jq -r '.id')
SELF_EXPR=$(printf '%s' '$' '{{ self.name }}')
printf 'id: %s\nname: summary-model\nversion: 1\ntags: {}\nattributes:\n run: "echo '\''Summary for %s: Processing completed'\''"\n workingDir: "/tmp"\n' "${SUMMARY_ID}" "${SELF_EXPR}" > "inputs/keeb/shell/${SUMMARY_ID}.yaml"

# Model 4: Final report referencing other models
../swamp model create keeb/shell final-report-model --json > /tmp/final.json
FINAL_ID=$(cat /tmp/final.json | jq -r '.id')
MODEL_DOWNLOAD_EXPR=$(printf '%s' '$' '{{ model.download-model.input.attributes.run }}')
MODEL_SUMMARY_EXPR=$(printf '%s' '$' '{{ model.summary-model.input.attributes.run }}')
printf 'id: %s\nname: final-report-model\nversion: 1\ntags: {}\nattributes:\n run: "echo '\''Final Report - Download: %s | Process result available | Summary: %s'\''"\n workingDir: "/tmp"\n' "${FINAL_ID}" "${MODEL_DOWNLOAD_EXPR}" "${MODEL_SUMMARY_EXPR}" > "inputs/keeb/shell/${FINAL_ID}.yaml"

# Model 5: Mermaid diagram generator (will consume workflow execution)
../swamp model create mermaid/workflow-diagram diagram-model --json > /tmp/diagram.json
DIAGRAM_ID=$(cat /tmp/diagram.json | jq -r '.id')
# Note: We'll populate this model's attributes after workflow execution

- name: Create integration test workflow
run: |
cd test-repo

../swamp workflow create integration-test --json > /tmp/workflow.json
WORKFLOW_ID=$(cat /tmp/workflow.json | jq -r '.id')

# Create workflow YAML file using printf
printf 'id: %s\nname: integration-test\ndescription: Integration test workflow with dependencies and cross-model references\njobs:\n - name: download\n description: Download sample data\n steps:\n - name: download-step\n task:\n type: model_method\n modelIdOrName: download-model\n methodName: execute\n - name: process\n description: Process downloaded data\n dependsOn:\n - job: download\n condition:\n type: succeeded\n ref: download\n steps:\n - name: process-step\n task:\n type: model_method\n modelIdOrName: process-model\n methodName: execute\n - name: summarize\n description: Create summary with self-reference\n dependsOn:\n - job: process\n condition:\n type: succeeded\n ref: process\n steps:\n - name: summary-step\n task:\n type: model_method\n modelIdOrName: summary-model\n methodName: execute\n - name: final-report\n description: Create final report with cross-model references\n dependsOn:\n - job: summarize\n condition:\n type: succeeded\n ref: summarize\n steps:\n - name: final-step\n task:\n type: model_method\n modelIdOrName: final-report-model\n methodName: execute\n' "${WORKFLOW_ID}" > "workflows/workflow-${WORKFLOW_ID}.yaml"

- name: Validate models and workflow
run: |
cd test-repo

# Validate all models
../swamp model validate download-model --json
../swamp model validate process-model --json
../swamp model validate summary-model --json
../swamp model validate final-report-model --json

# Validate workflow
../swamp workflow validate integration-test --json

- name: Execute integration workflow
run: |
cd test-repo

# Run the workflow and capture output
../swamp workflow run integration-test --json > workflow-output.json

# Display results
echo "=== Workflow Execution Results ==="
cat workflow-output.json | jq .

# Verify workflow succeeded
STATUS=$(cat workflow-output.json | jq -r '.status')
if [ "$STATUS" != "succeeded" ]; then
echo "ERROR: Workflow execution failed with status: $STATUS"
exit 1
fi

- name: Validate artifacts and dependencies
run: |
cd test-repo

# Check that all jobs completed successfully
JOB_STATUSES=$(cat workflow-output.json | jq -r '.jobs[] | "\(.name): \(.status)"')
echo "=== Job Statuses ==="
echo "$JOB_STATUSES"

# Verify no jobs failed
FAILED_JOBS=$(cat workflow-output.json | jq -r '.jobs[] | select(.status == "failed") | .name')
if [ -n "$FAILED_JOBS" ]; then
echo "ERROR: Failed jobs found: $FAILED_JOBS"
exit 1
fi

# Check that data artifacts were created
echo "=== Checking Data Artifacts ==="
find data -name "*.yaml" -exec echo "Found data: {}" \; 2>/dev/null || echo "No data directory found (expected for shell models)"

# Check that log artifacts were created
echo "=== Checking Log Artifacts ==="
find logs -name "*.log" -exec echo "Found log: {}" \; 2>/dev/null || echo "No logs directory found"

- name: Validate expression evaluation
run: |
cd test-repo

# Check that expressions were evaluated correctly by examining logs
echo "=== Validating Expression Evaluation ==="

# Look for evidence that self-reference worked in summary model
if grep -r "Summary for summary-model" logs/ 2>/dev/null; then
echo "✓ Self-reference expression evaluation succeeded"
else
echo "⚠ Could not verify self-reference evaluation (may be in data artifacts)"
fi

# Look for evidence that cross-model references worked in final report
if grep -r "Final Report - Download:" logs/ 2>/dev/null; then
echo "✓ Cross-model reference expression evaluation succeeded"
else
echo "⚠ Could not verify cross-model reference evaluation (may be in data artifacts)"
fi

echo "=== Integration Test Completed Successfully ==="

- name: Generate Mermaid workflow diagram
run: |
cd test-repo

echo "=== Generating Mermaid Diagram ==="

# Get the diagram model ID
DIAGRAM_ID=$(cat /tmp/diagram.json | jq -r '.id')

# Create input for diagram model using printf to avoid YAML parsing issues
printf 'id: DIAGRAM_ID_PLACEHOLDER\nname: diagram-model\nversion: 1\ntags: {}\nattributes:\n workflowExecution:\n workflowName: "integration-test"\n status: "succeeded"\n jobs:\n - name: "download"\n status: "succeeded"\n steps:\n - name: "download-step"\n status: "succeeded"\n task:\n type: "model_method"\n modelIdOrName: "download-model"\n methodName: "execute"\n - name: "process"\n status: "succeeded"\n dependsOn:\n - job: "download"\n condition:\n type: "succeeded"\n jobName: "download"\n steps:\n - name: "process-step"\n status: "succeeded"\n task:\n type: "model_method"\n modelIdOrName: "process-model"\n methodName: "execute"\n - name: "summarize"\n status: "succeeded"\n dependsOn:\n - job: "process"\n condition:\n type: "succeeded"\n jobName: "process"\n steps:\n - name: "summary-step"\n status: "succeeded"\n task:\n type: "model_method"\n modelIdOrName: "summary-model"\n methodName: "execute"\n - name: "final-report"\n status: "succeeded"\n dependsOn:\n - job: "summarize"\n condition:\n type: "succeeded"\n jobName: "summarize"\n steps:\n - name: "final-step"\n status: "succeeded"\n task:\n type: "model_method"\n modelIdOrName: "final-report-model"\n methodName: "execute"\n title: "Integration Test Workflow Execution"\n includeSteps: true\n colorScheme:\n succeeded: "#90EE90"\n failed: "#FFB6C1"\n cancelled: "#D3D3D3"\n skipped: "#FFFFE0"\n' > "/tmp/diagram-template.yaml"
# Replace placeholder and copy to final location
sed "s/DIAGRAM_ID_PLACEHOLDER/${DIAGRAM_ID}/g" "/tmp/diagram-template.yaml" > "inputs/mermaid/workflow-diagram/${DIAGRAM_ID}.yaml"

# Generate the Mermaid diagram
../swamp model method run diagram-model generate --json > diagram-output.json

# Display diagram generation result
echo "=== Diagram Generation Result ==="
cat diagram-output.json | jq .

# Copy generated diagram to artifacts directory
mkdir -p ../artifacts
if [ -d "files" ]; then
find files -name "*.mmd" -exec cp {} ../artifacts/ \;
echo "✓ Mermaid diagram copied to artifacts"
else
echo "⚠ No diagram files found"
fi

- name: Test error handling
run: |
cd test-repo

echo "=== Testing Error Handling ==="

# Create a workflow that should fail
../swamp model create keeb/shell failing-model --json > /tmp/failing.json
FAILING_ID=$(cat /tmp/failing.json | jq -r '.id')
printf 'id: %s\nname: failing-model\nversion: 1\ntags: {}\nattributes:\n run: "false"\n' "${FAILING_ID}" > "inputs/keeb/shell/${FAILING_ID}.yaml"

# Run the failing model and check the exit code in the output
../swamp model method run failing-model execute --json > failing-output.json
EXIT_CODE=$(cat failing-output.json | jq -r '.data.attributes.exitCode')
if [ "$EXIT_CODE" = "1" ]; then
echo "✓ Error handling works correctly - model command failed with exit code $EXIT_CODE"
else
echo "ERROR: Expected failing model command to have exitCode 1, but got: $EXIT_CODE"
cat failing-output.json | jq .
exit 1
fi

- name: Upload workflow artifacts
uses: actions/upload-artifact@v4
if: always() # Upload even if tests fail
with:
name: swamp-integration-test-artifacts
path: |
artifacts/
test-repo/workflow-output.json
test-repo/diagram-output.json
test-repo/logs/
test-repo/data/
test-repo/files/
test-repo/resources/
retention-days: 30

- name: Upload Mermaid diagram
uses: actions/upload-artifact@v4
if: always()
with:
name: workflow-diagram
path: |
artifacts/*.mmd
retention-days: 30
Loading
Loading