Files
twitter-cli-cookiefile/.github/workflows/publish-clawhub.yml
jackwener f31830f058 fix: fix ClawHub publish workflow
- Add export VERSION (NODE_ENV was not getting version)
- Fix API endpoint: api.clawhub.io → clawhub.ai
- Add NODE_TLS_REJECT_UNAUTHORIZED=0 for SSL cert issue
2026-03-11 01:11:54 +08:00

128 lines
4.4 KiB
YAML

name: Publish to ClawHub
on:
push:
tags:
- "v*"
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
env:
CLAWHUB_SLUG: twitter-cli
CLAWHUB_NAME: twitter-cli
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install ClawHub CLI
run: npm install -g clawhub@0.7.0
- name: Publish to ClawHub
env:
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
run: |
if [ -z "${CLAWHUB_TOKEN:-}" ]; then
echo "Missing required secret: CLAWHUB_TOKEN"
exit 1
fi
if [ "${GITHUB_REF_TYPE:-}" = "tag" ] && [ -n "${GITHUB_REF_NAME:-}" ]; then
VERSION="${GITHUB_REF_NAME#v}"
else
VERSION="$(sed -n 's/^version = \"\([^\"]*\)\"/\1/p' pyproject.toml | head -n 1)"
fi
if [ -z "${VERSION:-}" ]; then
echo "Unable to resolve version"
exit 1
fi
echo "Publishing ${CLAWHUB_SLUG}@${VERSION}"
if clawhub --no-input inspect "${CLAWHUB_SLUG}" --version "${VERSION}" >/dev/null 2>&1; then
echo "Version ${VERSION} already exists on ClawHub, skipping publish."
exit 0
fi
clawhub --no-input login --token "${CLAWHUB_TOKEN}" --no-browser
export VERSION
# Workaround: clawhub@0.7.0 publish doesn't send acceptLicenseTerms,
# which the server now requires. Use a Node.js script to publish with
# the corrected payload.
# Note: NODE_TLS_REJECT_UNAUTHORIZED=0 is needed because api.clawhub.io
# has an expired SSL certificate. Remove once ClawHub renews their cert.
NODE_TLS_REJECT_UNAUTHORIZED=0 node - <<'PUBLISH_SCRIPT'
const { resolve } = require("path");
const { readFileSync, statSync, readdirSync } = require("fs");
const folder = resolve(".");
const slug = process.env.CLAWHUB_SLUG;
const version = process.env.VERSION;
// Collect text files (same logic as clawhub CLI)
function walk(dir, base = "") {
let files = [];
for (const entry of readdirSync(dir, { withFileTypes: true })) {
const rel = base ? base + "/" + entry.name : entry.name;
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
if (entry.isDirectory()) { files.push(...walk(dir + "/" + entry.name, rel)); }
else { files.push({ rel, abs: dir + "/" + entry.name }); }
}
return files;
}
const files = walk(folder).filter(f => {
const ext = f.rel.split(".").pop().toLowerCase();
return ["md","txt","py","toml","yml","yaml","json","cfg","ini","sh","bat"].includes(ext);
});
const payload = JSON.stringify({
slug,
displayName: slug,
version,
changelog: "Release " + version,
tags: ["latest"],
acceptLicenseTerms: true,
});
const form = new FormData();
form.set("payload", payload);
for (const file of files) {
const bytes = readFileSync(file.abs);
const blob = new Blob([bytes], { type: "text/plain" });
form.append("files", blob, file.rel);
}
// Read registry and token from clawhub config
const os = require("os");
const configPath = resolve(os.homedir(), ".config", "clawhub", "config.json");
let token = "";
try {
const cfg = JSON.parse(readFileSync(configPath, "utf8"));
token = cfg.token || "";
} catch {}
if (!token) { console.error("No token found"); process.exit(1); }
const registry = "https://clawhub.ai";
fetch(registry + "/api/v1/skills", {
method: "POST",
headers: { Authorization: "Bearer " + token },
body: form,
}).then(async (r) => {
const text = await r.text();
if (!r.ok) {
console.error("Publish failed:", r.status, text);
process.exit(1);
}
console.log("✔ Published", slug + "@" + version);
}).catch((e) => {
console.error(e);
process.exit(1);
});
PUBLISH_SCRIPT