Skip to content

Commit 72a3cd2

Browse files
authored
feat(openclaw-plugin): support OpenClaw install and ClawHub release flow (#1904)
Squashes OpenClaw plugin install compatibility, setup helper source-build support, built dist output, and ClawHub release workflow updates into one publish commit. Co-authored-by: LinQiang391 <linqiang391@users.noreply.github.com>
1 parent 833dc59 commit 72a3cd2

26 files changed

Lines changed: 3728 additions & 500 deletions
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
name: ClawHub release (OpenViking plugin)
2+
3+
# Publishes examples/openclaw-plugin to ClawHub. The publish branch
4+
# intentionally does not commit dist/; this workflow builds and npm-packs the
5+
# plugin into a generated package branch, then lets ClawHub's official reusable
6+
# workflow perform trusted publishing from that package source while preserving
7+
# the original workflow commit as source metadata.
8+
9+
on:
10+
workflow_dispatch:
11+
inputs:
12+
version:
13+
description: "Optional plugin version. Leave empty to auto-generate YYYY.M.D / YYYY.M.D-N / YYYY.M.D-dev.N."
14+
required: false
15+
channel:
16+
description: "Publish channel. auto publishes latest from the configured upstream repository and dev from forks."
17+
required: false
18+
type: choice
19+
default: "auto"
20+
options:
21+
- auto
22+
- dev
23+
- latest
24+
changelog:
25+
description: "Changelog text for this release."
26+
required: false
27+
default: "OpenViking plugin release via OIDC trusted publishing."
28+
29+
permissions:
30+
contents: read
31+
32+
jobs:
33+
guard:
34+
name: Resolve release channel
35+
runs-on: ubuntu-latest
36+
permissions:
37+
contents: read
38+
outputs:
39+
tags: ${{ steps.resolve.outputs.tags }}
40+
version: ${{ steps.resolve.outputs.version }}
41+
steps:
42+
- name: Resolve release channel and version
43+
id: resolve
44+
shell: bash
45+
run: |
46+
repo="${{ github.repository }}"
47+
requested="${{ github.event.inputs.channel || 'auto' }}"
48+
requested_version="${{ github.event.inputs.version || '' }}"
49+
configured_upstream="${{ vars.CLAWHUB_UPSTREAM_REPOSITORY }}"
50+
configured_latest_repos="${{ vars.CLAWHUB_LATEST_REPOSITORIES }}"
51+
configured_dev_repos="${{ vars.CLAWHUB_DEV_REPOSITORIES }}"
52+
configured_timezone="${{ vars.CLAWHUB_RELEASE_TIMEZONE }}"
53+
upstream_repo="${configured_upstream:-volcengine/OpenViking}"
54+
release_timezone="${configured_timezone:-Asia/Shanghai}"
55+
56+
repo_in_list() {
57+
local needle="$1"
58+
local list="${2//,/ }"
59+
for item in $list; do
60+
if [ "$item" = "$needle" ]; then
61+
return 0
62+
fi
63+
done
64+
return 1
65+
}
66+
67+
can_publish_latest=false
68+
if [ "$repo" = "$upstream_repo" ] || repo_in_list "$repo" "$configured_latest_repos"; then
69+
can_publish_latest=true
70+
fi
71+
72+
can_publish_dev=true
73+
if [ "$repo" = "$upstream_repo" ]; then
74+
can_publish_dev=true
75+
elif [ -n "$configured_dev_repos" ] && ! repo_in_list "$repo" "$configured_dev_repos"; then
76+
can_publish_dev=false
77+
fi
78+
79+
if [ "$requested" = "auto" ]; then
80+
if [ "$can_publish_latest" = "true" ]; then
81+
channel="latest"
82+
elif [ "$can_publish_dev" = "true" ]; then
83+
channel="dev"
84+
else
85+
echo "::error title=Repository not allowed::Repository '$repo' is not allowed to publish to ClawHub. Set CLAWHUB_DEV_REPOSITORIES or CLAWHUB_LATEST_REPOSITORIES repository variables if this is intentional."
86+
exit 1
87+
fi
88+
else
89+
channel="$requested"
90+
fi
91+
92+
if [ "$channel" != "dev" ] && [ "$channel" != "latest" ]; then
93+
echo "::error title=Invalid channel::Unsupported ClawHub channel '$channel'."
94+
exit 1
95+
fi
96+
97+
if [ "$channel" = "latest" ] && [ "$can_publish_latest" != "true" ]; then
98+
echo "::error title=Refusing to publish::Repository '$repo' may not publish the latest channel. Only '$upstream_repo' and repositories listed in CLAWHUB_LATEST_REPOSITORIES may publish latest."
99+
exit 1
100+
fi
101+
102+
if [ "$channel" = "dev" ] && [ "$can_publish_dev" != "true" ]; then
103+
echo "::error title=Refusing to publish::Repository '$repo' may not publish the dev channel. Configure CLAWHUB_DEV_REPOSITORIES if this repository should be allowed."
104+
exit 1
105+
fi
106+
107+
collect_published_versions() {
108+
local target_repo="$1"
109+
local remote="https://x-access-token:${{ github.token }}@github.com/${target_repo}.git"
110+
local tmpdir
111+
tmpdir="$(mktemp -d)"
112+
git -C "$tmpdir" init -q
113+
git -C "$tmpdir" remote add origin "$remote"
114+
if git -C "$tmpdir" fetch --quiet --depth=1 origin '+refs/heads/clawhub-package-*:refs/remotes/origin/clawhub-package-*'; then
115+
git -C "$tmpdir" for-each-ref --format='%(refname)' refs/remotes/origin/clawhub-package-* | while IFS= read -r ref; do
116+
branch_version="$(
117+
git -C "$tmpdir" show "$ref:package.json" 2>/dev/null \
118+
| sed -n 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \
119+
| head -n 1 || true
120+
)"
121+
if [ -n "$branch_version" ]; then
122+
echo "$branch_version"
123+
fi
124+
done
125+
fi
126+
rm -rf "$tmpdir"
127+
}
128+
129+
next_version_for_channel() {
130+
local channel="$1"
131+
local base_version
132+
local existing_versions
133+
base_version="$(TZ="$release_timezone" date +'%Y.%-m.%-d')"
134+
existing_versions="$(collect_published_versions "$repo" | sort -u)"
135+
136+
if [ "$channel" = "dev" ]; then
137+
local prefix="${base_version}-dev."
138+
local max_dev=0
139+
while IFS= read -r candidate; do
140+
if [[ "$candidate" == "$prefix"* ]]; then
141+
local suffix="${candidate#$prefix}"
142+
if [[ "$suffix" =~ ^[0-9]+$ ]] && [ "$((10#$suffix))" -gt "$max_dev" ]; then
143+
max_dev="$((10#$suffix))"
144+
fi
145+
fi
146+
done <<< "$existing_versions"
147+
echo "${base_version}-dev.$((max_dev + 1))"
148+
return
149+
fi
150+
151+
local max_latest=-1
152+
while IFS= read -r candidate; do
153+
if [ "$candidate" = "$base_version" ]; then
154+
if [ "$max_latest" -lt 0 ]; then
155+
max_latest=0
156+
fi
157+
elif [[ "$candidate" == "${base_version}-"* ]]; then
158+
local suffix="${candidate#${base_version}-}"
159+
if [[ "$suffix" =~ ^[0-9]+$ ]] && [ "$((10#$suffix))" -gt "$max_latest" ]; then
160+
max_latest="$((10#$suffix))"
161+
fi
162+
fi
163+
done <<< "$existing_versions"
164+
165+
if [ "$max_latest" -lt 0 ]; then
166+
echo "$base_version"
167+
else
168+
echo "${base_version}-$((max_latest + 1))"
169+
fi
170+
}
171+
172+
if [ -n "$requested_version" ]; then
173+
version="$requested_version"
174+
else
175+
version="$(next_version_for_channel "$channel")"
176+
fi
177+
178+
if [ "$channel" = "dev" ] && [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+-dev\.[0-9]+$ ]]; then
179+
echo "::error title=Invalid dev version::The dev channel requires YYYY.M.D-dev.N, got '$version'."
180+
exit 1
181+
fi
182+
183+
if [ "$channel" = "latest" ] && [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$ ]]; then
184+
echo "::error title=Invalid latest version::The latest channel requires YYYY.M.D or YYYY.M.D-N, got '$version'."
185+
exit 1
186+
fi
187+
188+
echo "tags=$channel" >> "$GITHUB_OUTPUT"
189+
echo "version=$version" >> "$GITHUB_OUTPUT"
190+
191+
- name: Show inputs
192+
run: |
193+
echo "requested_version=${{ github.event.inputs.version || '' }}"
194+
echo "resolved_version=${{ steps.resolve.outputs.version }}"
195+
echo "channel=${{ github.event.inputs.channel || 'auto' }}"
196+
echo "resolved_tags=${{ steps.resolve.outputs.tags }}"
197+
echo "changelog=${{ github.event.inputs.changelog || 'OpenViking plugin release via OIDC trusted publishing.' }}"
198+
199+
prepare-package-source:
200+
name: Prepare ClawHub package source
201+
needs: guard
202+
runs-on: ubuntu-latest
203+
timeout-minutes: 15
204+
permissions:
205+
contents: write
206+
outputs:
207+
package_branch: ${{ steps.package_branch.outputs.branch }}
208+
source_url: ${{ steps.package_branch.outputs.source_url }}
209+
steps:
210+
- uses: actions/checkout@v6
211+
with:
212+
ref: ${{ github.sha }}
213+
214+
- uses: actions/setup-node@v6
215+
with:
216+
node-version: 22
217+
cache: npm
218+
cache-dependency-path: examples/openclaw-plugin/package-lock.json
219+
220+
- name: Pack OpenViking plugin
221+
id: pack
222+
working-directory: examples/openclaw-plugin
223+
env:
224+
VERSION: ${{ needs.guard.outputs.version }}
225+
run: |
226+
set -euo pipefail
227+
npm version --no-git-tag-version --allow-same-version "$VERSION"
228+
npm ci
229+
pack_dir="$RUNNER_TEMP/openviking-pack"
230+
package_dir="$RUNNER_TEMP/openviking-package"
231+
mkdir -p "$pack_dir" "$package_dir"
232+
npm pack --pack-destination "$pack_dir"
233+
tarball="$(find "$pack_dir" -maxdepth 1 -name '*.tgz' -print -quit)"
234+
if [ -z "$tarball" ]; then
235+
echo "::error title=Pack failed::npm pack did not produce a tgz file."
236+
exit 1
237+
fi
238+
tar -xzf "$tarball" -C "$package_dir"
239+
echo "package_dir=$package_dir/package" >> "$GITHUB_OUTPUT"
240+
find "$package_dir/package" -maxdepth 3 -type f | sort
241+
242+
- name: Push generated package branch
243+
id: package_branch
244+
env:
245+
PACKAGE_DIR: ${{ steps.pack.outputs.package_dir }}
246+
VERSION: ${{ needs.guard.outputs.version }}
247+
BRANCH: clawhub-package-${{ github.run_id }}
248+
run: |
249+
set -euo pipefail
250+
git config user.name "github-actions[bot]"
251+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
252+
git switch --orphan "$BRANCH"
253+
git rm -r --cached . || true
254+
find . -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} +
255+
cp -a "$PACKAGE_DIR"/. .
256+
git add .
257+
git commit -m "chore(clawhub): package openviking plugin $VERSION"
258+
git push --force origin "HEAD:$BRANCH"
259+
source_url="${GITHUB_REPOSITORY}@${BRANCH}"
260+
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
261+
echo "source_url=$source_url" >> "$GITHUB_OUTPUT"
262+
echo "source_url=$source_url"
263+
264+
publish:
265+
name: Publish to ClawHub (official trusted workflow)
266+
needs:
267+
- guard
268+
- prepare-package-source
269+
permissions:
270+
contents: read
271+
id-token: write
272+
uses: openclaw/clawhub/.github/workflows/package-publish.yml@v0.12.0
273+
with:
274+
source: ${{ needs.prepare-package-source.outputs.source_url }}
275+
dry_run: false
276+
json: true
277+
version: ${{ needs.guard.outputs.version }}
278+
tags: ${{ needs.guard.outputs.tags }}
279+
source_repo: ${{ github.repository }}
280+
source_commit: ${{ github.sha }}
281+
source_ref: ${{ github.ref }}

examples/openclaw-plugin/.clawhubignore

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ __tests__/
44
images/
55
health_check_tools/
66
upgrade_scripts/
7-
skills/
87
INSTALL*.md
9-
README*.md
8+
README_CN.md
109
install.sh
1110
vitest.config.ts
11+
# Excluded so ClawHub CLI's bundle marker pre-scan does not misclassify this
12+
# code-plugin as a bundle-plugin. The later npm pack step still includes
13+
# commands/setup.ts and skills/ through package.json "files".
14+
commands/
15+
skills/
16+
*.tgz

0 commit comments

Comments
 (0)