Skip to content

Merge pull request #6 from fourdollars/dependabot/github_actions/acti… #89

Merge pull request #6 from fourdollars/dependabot/github_actions/acti…

Merge pull request #6 from fourdollars/dependabot/github_actions/acti… #89

Workflow file for this run

name: Charm Tests
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
workflow_dispatch:
jobs:
lint:
name: Lint Charm Code
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y shellcheck
- name: Lint shell scripts
run: |
find hooks -type f -executable -exec shellcheck {} +
- name: Check hook permissions
run: |
for hook in hooks/*; do
if [ -f "$hook" ] && [ ! -x "$hook" ]; then
echo "ERROR: Hook $hook is not executable"
exit 1
fi
done
- name: Validate metadata
run: |
if [ ! -f metadata.yaml ]; then
echo "ERROR: metadata.yaml not found"
exit 1
fi
# Check required fields
for field in name summary description; do
if ! grep -q "^${field}:" metadata.yaml; then
echo "ERROR: Required field '${field}' not found in metadata.yaml"
exit 1
fi
done
- name: Validate config
run: |
if [ ! -f config.yaml ]; then
echo "ERROR: config.yaml not found"
exit 1
fi
build:
name: Build Charm
runs-on: ubuntu-24.04
needs: lint
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install charmcraft
run: |
sudo snap install charmcraft --classic
- name: Pack charm
run: |
charmcraft pack --destructive-mode
- name: Upload charm artifact
uses: actions/upload-artifact@v4
with:
name: openclaw-charm
path: openclaw_*.charm
retention-days: 1
test-install:
name: Test Charm Installation
runs-on: ubuntu-24.04
needs: build
strategy:
matrix:
install-method: [npm, pnpm, bun]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download charm artifact
uses: actions/download-artifact@v7
with:
name: openclaw-charm
- name: Set up LXD
uses: canonical/setup-lxd@main
with:
channel: latest/stable
- name: Install Juju
run: |
sudo snap install juju --channel=3/stable
sudo snap install juju-wait --classic
- name: Bootstrap Juju
run: |
lxc network set lxdbr0 ipv6.address none
juju bootstrap localhost test-controller
- name: Create test model
run: |
juju add-model test-openclaw
- name: Deploy charm
run: |
CHARM_FILE=$(ls openclaw_*.charm | head -1)
juju deploy ./$CHARM_FILE \
--config install-method=${{ matrix.install-method }} \
--config ai-provider="anthropic" \
--config ai-model="claude-sonnet-3-5" \
--config ai-api-key="test-key-placeholder"
- name: Wait for deployment
run: |
# Wait up to 15 minutes for installation to complete
juju-wait -v -m test-openclaw -t 900
- name: Verify installation
run: |
# Get unit IP
UNIT_IP=$(juju status openclaw --format=json | jq -r '.applications.openclaw.units | to_entries[0].value."public-address"')
echo "Unit IP: $UNIT_IP"
# Check if openclaw command exists
juju ssh openclaw/0 'which openclaw'
# Check openclaw version
juju ssh openclaw/0 'openclaw --version' || echo "Version check skipped (may require config)"
# Check systemd service
juju ssh openclaw/0 'systemctl status openclaw.service' || true
# Check if port is open
juju ssh openclaw/0 'ss -tulpn | grep 18789' || echo "Port not bound (expected without valid API key)"
- name: Test configuration changes
run: |
# Change gateway port
juju config openclaw gateway-port=18790
# Wait for config change to apply
sleep 30
# Verify port change
juju ssh openclaw/0 'ss -tulpn | grep 18790' || echo "Port change test (may not bind without valid key)"
# Change back
juju config openclaw gateway-port=18789
- name: Collect logs on failure
if: failure()
run: |
echo "=== Juju Status ==="
juju status --format=yaml
echo "=== Debug Log ==="
juju debug-log --replay --no-tail --limit 500
echo "=== Unit Logs ==="
juju ssh openclaw/0 'journalctl -u openclaw.service -n 200' || true
echo "=== OpenClaw Config ==="
juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json' || true
- name: Cleanup
if: always()
run: |
juju destroy-model test-openclaw -y --force --no-wait || true
juju destroy-controller test-controller -y --destroy-all-models --force --no-wait || true
test-channels:
name: Test Messaging Channel Configuration
runs-on: ubuntu-24.04
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download charm artifact
uses: actions/download-artifact@v7
with:
name: openclaw-charm
- name: Set up LXD
uses: canonical/setup-lxd@main
- name: Install Juju
run: |
sudo snap install juju --channel=3/stable
sudo snap install juju-wait --classic
- name: Bootstrap Juju
run: |
lxc network set lxdbr0 ipv6.address none
juju bootstrap localhost test-controller
- name: Create test model
run: |
juju add-model test-channels
- name: Deploy with channel config
run: |
CHARM_FILE=$(ls openclaw_*.charm | head -1)
juju deploy ./$CHARM_FILE \
--config ai-provider="anthropic" \
--config ai-model="claude-sonnet-3-5" \
--config ai-api-key="test-key" \
--config telegram-bot-token="123456:TEST"
- name: Wait for deployment
run: |
juju-wait -v -m test-channels -t 900
- name: Verify channel configuration
run: |
# Check that config file contains channel configuration
juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json' > config.json
if grep -q "telegram" config.json; then
echo "✓ Channel configuration verified"
else
echo "✗ Channel configuration missing"
exit 1
fi
- name: Cleanup
if: always()
run: |
juju destroy-model test-channels -y --force --no-wait || true
juju destroy-controller test-controller -y --destroy-all-models --force --no-wait || true
test-upgrade:
name: Test Charm Upgrade
runs-on: ubuntu-24.04
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download charm artifact
uses: actions/download-artifact@v7
with:
name: openclaw-charm
- name: Set up LXD
uses: canonical/setup-lxd@main
- name: Install Juju
run: |
sudo snap install juju --channel=3/stable
sudo snap install juju-wait --classic
- name: Bootstrap Juju
run: |
lxc network set lxdbr0 ipv6.address none
juju bootstrap localhost test-controller
- name: Create test model
run: |
juju add-model test-upgrade
- name: Deploy v1
run: |
CHARM_FILE=$(ls openclaw_*.charm | head -1)
juju deploy ./$CHARM_FILE \
--config ai-provider="anthropic" \
--config ai-model="claude-sonnet-3-5" \
--config ai-api-key="test-key"
- name: Wait for initial deployment
run: |
juju-wait -v -m test-upgrade -t 900
- name: Refresh charm (simulate upgrade)
run: |
CHARM_FILE=$(ls openclaw_*.charm | head -1)
juju refresh openclaw --path ./$CHARM_FILE
sleep 60 # Give upgrade-charm hook time to complete
- name: Verify upgrade success
run: |
# Get unit workload status (field is "current", not "status")
status=$(juju status openclaw --format=json | jq -r '.applications.openclaw.units[]["workload-status"].current' | head -1)
echo "Current workload status: $status"
if [ "$status" = "active" ] || [ "$status" = "blocked" ]; then
echo "✓ Upgrade successful (status: $status)"
else
echo "✗ Upgrade failed - unexpected status: $status"
echo "Full juju status:"
juju status openclaw
exit 1
fi
- name: Cleanup
if: always()
run: |
juju destroy-model test-upgrade -y --force --no-wait || true
juju destroy-controller test-controller -y --destroy-all-models --force --no-wait || true
test-manual-mode:
name: Test Manual Configuration Mode
runs-on: ubuntu-24.04
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download charm artifact
uses: actions/download-artifact@v7
with:
name: openclaw-charm
- name: Set up LXD
uses: canonical/setup-lxd@main
- name: Install Juju
run: |
sudo snap install juju --channel=3/stable
sudo snap install juju-wait --classic
- name: Bootstrap Juju
run: |
lxc network set lxdbr0 ipv6.address none
juju bootstrap localhost test-controller
- name: Create test model
run: |
juju add-model test-manual
- name: Deploy with manual=true
run: |
CHARM_FILE=$(ls openclaw_*.charm | head -1)
juju deploy ./$CHARM_FILE \
--config manual=true \
--config install-method=npm
- name: Wait for deployment
run: |
juju-wait -v -m test-manual -t 900
- name: Verify manual mode behavior
run: |
# Check status message indicates manual mode
status_msg=$(juju status openclaw --format=json | jq -r '.applications.openclaw.units[]["workload-status"].message' | head -1)
echo "Status message: $status_msg"
if echo "$status_msg" | grep -qi "manual"; then
echo "✓ Manual mode status verified"
else
echo "✗ Status does not indicate manual mode: $status_msg"
exit 1
fi
# Verify OpenClaw is installed
juju ssh openclaw/0 'sudo -u ubuntu bash -l -c ". ~/.nvm/nvm.sh && nvm use 24 && which openclaw"'
echo "✓ OpenClaw binary installed"
# Verify version
version=$(juju ssh openclaw/0 'sudo -u ubuntu bash -l -c ". ~/.nvm/nvm.sh && nvm use 24 && openclaw --version 2>&1 | tail -1"')
echo "OpenClaw version: $version"
# Check that config files were NOT auto-generated by charm
if juju ssh openclaw/0 'test -f /home/ubuntu/.openclaw/openclaw.json'; then
echo "⚠ Config file exists (may be from OpenClaw itself, not charm)"
# Verify it doesn't contain charm-managed settings
if juju ssh openclaw/0 'grep -q "ai-provider\|ai-model" /home/ubuntu/.openclaw/openclaw.json 2>/dev/null'; then
echo "✗ Config contains charm-managed settings in manual mode"
exit 1
fi
fi
echo "✓ No charm-managed config generated"
- name: Test user config preservation
run: |
# Create a custom config file
juju ssh openclaw/0 'cat > /tmp/custom-config.json << "EOF"
{
"user_custom_field": "test-value-12345",
"gateway": {
"mode": "local",
"port": 18789
}
}
EOF'
# Copy it to OpenClaw directory
juju ssh openclaw/0 'sudo -u ubuntu cp /tmp/custom-config.json /home/ubuntu/.openclaw/openclaw.json'
# Trigger a config change (this would normally regenerate config in automatic mode)
juju config openclaw gateway-port=18790
sleep 30
# Verify custom field still exists
if juju ssh openclaw/0 'grep -q "user_custom_field.*test-value-12345" /home/ubuntu/.openclaw/openclaw.json'; then
echo "✓ User config preserved after charm config change"
else
echo "✗ User config was overwritten"
juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json'
exit 1
fi
- name: Test multi-unit with manual mode
run: |
# Add a second unit
juju add-unit openclaw
# Wait for it to deploy
timeout 900 bash -c 'until juju status openclaw --format=json | jq -e ".applications.openclaw.units[\"openclaw/1\"]" > /dev/null 2>&1; do sleep 10; done'
sleep 60 # Additional wait for installation
# Check second unit has manual mode
unit1_status=$(juju status openclaw --format=json | jq -r '.applications.openclaw.units["openclaw/1"]["workload-status"].message' 2>/dev/null || echo "not-ready")
echo "Unit 1 status: $unit1_status"
# Verify OpenClaw installed on second unit
juju ssh openclaw/1 'sudo -u ubuntu bash -l -c ". ~/.nvm/nvm.sh && nvm use 24 && which openclaw"' || echo "Unit 1 still installing"
# Verify peer relation node config exists on Node unit
if juju ssh openclaw/1 'test -f /home/ubuntu/.openclaw/node.json'; then
echo "✓ Node peer relation config exists"
juju ssh openclaw/1 'cat /home/ubuntu/.openclaw/node.json'
else
echo "⚠ Node config not yet created (unit may still be starting)"
fi
- name: Collect logs on failure
if: failure()
run: |
echo "=== Juju Status ==="
juju status --format=yaml
echo "=== Debug Log ==="
juju debug-log --replay --no-tail --limit 500
echo "=== Unit 0 Config ==="
juju ssh openclaw/0 'ls -la /home/ubuntu/.openclaw/' || true
juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json 2>/dev/null' || true
echo "=== Unit 1 Config ==="
juju ssh openclaw/1 'ls -la /home/ubuntu/.openclaw/' || true
juju ssh openclaw/1 'cat /home/ubuntu/.openclaw/node.json 2>/dev/null' || true
- name: Cleanup
if: always()
run: |
juju destroy-model test-manual -y --force --no-wait || true
juju destroy-controller test-controller -y --destroy-all-models --force --no-wait || true