Skip to content

feat(integrations): add Dify plugin with E2E testing #1

feat(integrations): add Dify plugin with E2E testing

feat(integrations): add Dify plugin with E2E testing #1

name: Dify Plugin E2E
on:
pull_request:
branches: [main]
paths:
- 'integrations/dify-plugin/**'
- 'tests/e2e/dify_plugin/**'
- 'sdks/sandbox/python/**'
- 'server/**'
push:
branches: [main, 'feat/**', 'feature/**']
paths:
- 'integrations/dify-plugin/**'
- 'tests/e2e/dify_plugin/**'
- 'sdks/sandbox/python/**'
- 'server/**'
- '.github/workflows/dify-plugin-e2e.yml'
workflow_dispatch:
# Allow manual trigger from GitHub Actions UI
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
DIFY_PORT: "5001"
DIFY_REF: "main"
DIFY_ADMIN_EMAIL: "admin@example.com"
DIFY_ADMIN_PASSWORD: "ChangeMe123!"
OPEN_SANDBOX_API_KEY: "opensandbox-e2e-key"
jobs:
dify-plugin-e2e:
name: Dify Plugin E2E Test
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
run: pip install uv
- name: Build execd image
working-directory: components/execd
run: |
docker build -t opensandbox/execd:local .
- name: Create OpenSandbox config
run: |
cat > ~/.sandbox.toml <<EOF
[server]
host = "0.0.0.0"
port = 8080
log_level = "INFO"
api_key = "${{ env.OPEN_SANDBOX_API_KEY }}"
[runtime]
type = "docker"
execd_image = "opensandbox/execd:local"
[docker]
network_mode = "bridge"
EOF
- name: Install OpenSandbox server dependencies
working-directory: server
run: uv sync
- name: Start OpenSandbox server
working-directory: server
run: |
uv run python -m src.main > server.log 2>&1 &
echo "OPENSANDBOX_PID=$!" >> $GITHUB_ENV
- name: Wait for OpenSandbox server
run: |
for i in {1..30}; do
if curl -s http://localhost:8080/health | grep -q healthy; then
echo "OpenSandbox server is ready"
exit 0
fi
echo "Waiting for OpenSandbox server... ($i/30)"
sleep 2
done
echo "OpenSandbox server failed to start"
cat server/server.log
exit 1
- name: Prepare Dify docker-compose
working-directory: tests/e2e/dify_plugin
env:
DIFY_REF: ${{ env.DIFY_REF }}
run: |
python prepare_dify_compose.py
echo "Dify compose files ready"
- name: Start Dify
working-directory: tests/e2e/dify_plugin/.dify
run: |
docker compose up -d
echo "Dify containers starting..."
- name: Wait for Dify API
run: |
for i in {1..90}; do
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:${{ env.DIFY_PORT }}/console/api/ping 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "200" ]; then
echo "Dify API is ready (HTTP 200)"
exit 0
fi
echo "Waiting for Dify API... ($i/90) HTTP=$HTTP_CODE"
sleep 5
done
echo "Dify API failed to start"
docker compose -f tests/e2e/dify_plugin/.dify/docker-compose.yaml logs
exit 1
- name: Install OpenSandbox Python SDK (local)
working-directory: sdks/sandbox/python
run: |
pip install -e .
- name: Install plugin dependencies
working-directory: integrations/dify-plugin/opensandbox
run: |
pip install -r requirements.txt
- name: Install e2e test dependencies
working-directory: tests/e2e/dify_plugin
run: |
pip install -r requirements.txt
- name: Run E2E test
working-directory: tests/e2e/dify_plugin
env:
DIFY_CONSOLE_API_URL: "http://localhost:${{ env.DIFY_PORT }}"
# Plugin runs on host via remote debug, so localhost works
OPEN_SANDBOX_BASE_URL: "http://localhost:8080"
run: |
python run_e2e.py
- name: Upload OpenSandbox logs
if: always()
uses: actions/upload-artifact@v4
with:
name: opensandbox-server-log
path: server/server.log
retention-days: 5
- name: Collect Dify logs
if: always()
run: |
docker compose -f tests/e2e/dify_plugin/.dify/docker-compose.yaml logs > dify.log 2>&1 || true
- name: Upload Dify logs
if: always()
uses: actions/upload-artifact@v4
with:
name: dify-logs
path: dify.log
retention-days: 5
- name: Cleanup
if: always()
run: |
docker compose -f tests/e2e/dify_plugin/.dify/docker-compose.yaml down --volumes --remove-orphans || true
kill ${{ env.OPENSANDBOX_PID }} 2>/dev/null || true