Repository navigation
118 lines (110 loc) · 5.55 KB
/
Copy pathsample-plugin-e2e.yml
File metadata and controls
118 lines (110 loc) · 5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# Devkit self-test: run the full lifecycle against the bundled sample plugin on
# a GitHub runner. Self-contained (the devkit IS the devkit here — no submodule,
# no App token), so it exercises the HARNESS. The consumer DISTRIBUTION path
# (devkit submodule + App-token + reusable plugin-e2e.yml) is exercised by
# onboarding a real plugin repo (e.g. livekit).
name: sample-plugin-e2e
on:
push:
branches: ["main", "feat/devkit-sync-distribution"]
pull_request:
branches: ["main"]
workflow_dispatch:
jobs:
sample-e2e:
runs-on: ubuntu-latest
timeout-minutes: 40
permissions:
contents: read
# actions:write is needed ONLY to DELETE superseded artifacts for the
# count-based retention prune (DEC-074).
actions: write
env:
ARTIFACT_KEEP: 5
steps:
- uses: actions/checkout@v4
- name: Free disk space
# The fork image (ghcr.io/nuevanext/agent-zero, bundles ML deps e.g.
# onnxruntime) is larger than upstream's 8.76GB and exhausts the runner
# disk during the nested unpack. Reclaim ~30GB of preinstalled tooling.
run: |
df -h / | tail -1
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/.ghcup \
/usr/local/lib/android /opt/hostedtoolcache/CodeQL \
/usr/local/share/boost "$AGENT_TOOLSDIRECTORY" 2>/dev/null || true
sudo docker image prune -af 2>/dev/null || true
echo "after reclaim:"; df -h / | tail -1
- name: Build devcontainer (rootless)
run: podman build -t plugin-devkit:ci -f devcontainer/Containerfile devcontainer
- name: Package sample + run lifecycle (A0 nested, unprivileged)
# Boots the PUBLIC upstream image (docker.io/agent0ai/agent-zero:latest) —
# the A0_IMAGE default from DEC-019. This job must pass with NO secrets:
# dependabot runs and fork PRs from outside contributors never receive
# them, so pinning the private fork image here made this workflow red for
# everyone outside the org. Consumers that need the ML-bundled fork still
# override A0_IMAGE per-plugin via .devkit.yml.
run: |
set -euo pipefail
mkdir -p dist "$GITHUB_WORKSPACE/artifacts"
chmod 777 "$GITHUB_WORKSPACE/artifacts" # rootless-podman maps the container user to a subuid; 777 lets it write
( cd examples/sample-plugin && zip -qr "$GITHUB_WORKSPACE/dist/sample_plugin.zip" . -x 'tests/*' )
podman run --rm \
--device /dev/fuse \
--security-opt label=disable \
--sysctl net.ipv4.ip_unprivileged_port_start=0 \
-v "$GITHUB_WORKSPACE":/workspace:ro \
-v "$GITHUB_WORKSPACE/dist/sample_plugin.zip":/tmp/plugin.zip:ro \
-v "$GITHUB_WORKSPACE/artifacts":/artifacts:rw \
-e PLUGIN_ZIP=/tmp/plugin.zip \
-e PLUGIN_DISPLAY_NAME="Sample Plugin" \
-e PLUGIN_NAME=sample_plugin \
-e HOOK_DIR=/workspace/examples/sample-plugin/tests/e2e/hooks \
-e BEHAVIOUR_FILE=/workspace/examples/sample-plugin/tests/e2e/behaviour.mjs \
-e A0_IMAGE="docker.io/agent0ai/agent-zero:latest" \
-e ARTIFACT_DIR=/artifacts \
plugin-devkit:ci \
-lc 'bash /workspace/e2e/harness/run-lifecycle.sh'
- name: Convert lifecycle video → GIF + upload recording
if: always()
run: |
set -uo pipefail
shopt -s nullglob
sudo chown -R "$USER" artifacts 2>/dev/null || true
if ! command -v ffmpeg >/dev/null 2>&1; then sudo apt-get update -qq && sudo apt-get install -y -qq ffmpeg; fi
for webm in artifacts/*.webm; do
base="${webm%.webm}"
ffmpeg -y -i "$webm" -vf "fps=6,scale=1024:-1:flags=lanczos,palettegen" /tmp/pal.png 2>/dev/null || continue
ffmpeg -y -i "$webm" -i /tmp/pal.png -lavfi "fps=6,scale=1024:-1:flags=lanczos[x];[x][1:v]paletteuse" "$base.gif" 2>/dev/null || true
echo "GIF: $base.gif ($(du -h "$base.gif" 2>/dev/null | cut -f1))"
done
ls -la artifacts/ || true
- name: Upload e2e recording
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-recording-sample
path: artifacts/
if-no-files-found: warn
# Backstop only. The real policy is count-based (keep last N runs) and
# is enforced by the prune step below — GitHub has NO native "keep last
# N artifacts" setting, retention-days is the only built-in control.
# Kept long so the prune step, not expiry, decides what disappears.
retention-days: 90
- name: Prune old e2e recordings (keep last N runs)
# Count-based retention (DEC-074), mirroring the reusable plugin-e2e.yml.
# Without this the self-test workflow accumulates one artifact per run
# forever (25 live before this was added), and time-based expiry — not
# the policy — decides what survives.
#
# On fork PRs the token is read-only, so deletion is skipped rather than
# failing the run; the step is continue-on-error so retention housekeeping
# can never turn a green e2e red.
if: always()
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
KEEP: ${{ env.ARTIFACT_KEEP }}
ART_NAME: e2e-recording-sample
IS_FORK: ${{ github.event.pull_request.head.repo.fork || false }}
# Single definition, shared with the reusable plugin-e2e.yml.
run: bash e2e/ci/prune-artifacts.sh