fix(publish): auto-discover packages + pre-publish test gate
What: Replace hardcoded PUBLISH_ORDER with auto-discovery of all non-private packages, sorted by topological dependency order (Kahn's). Add a test gate (npm test) after build, before publish. Why: The manual list was missing workflow-gateway and workflow-agent-react, causing them to never get published. Any future package additions would have the same problem. Changes: - scripts/publish.sh: Replace static PUBLISH_ORDER array with node script that reads all packages/*/package.json, filters out private, and topologically sorts by @uncaged/* internal dependencies - scripts/publish.sh: Add npm test step between build and publish, aborting on failure
This commit is contained in:
+90
-18
@@ -36,23 +36,53 @@ CURRENT=$(current_version)
|
|||||||
VERSION=$(bump_version "$CURRENT" "${1:?Usage: publish.sh <version|patch|minor|major>}")
|
VERSION=$(bump_version "$CURRENT" "${1:?Usage: publish.sh <version|patch|minor|major>}")
|
||||||
echo "📦 Publish: $CURRENT → $VERSION"
|
echo "📦 Publish: $CURRENT → $VERSION"
|
||||||
|
|
||||||
# ─── Topological publish order ───────────────────────────────────────────────
|
# ─── Auto-discover publishable packages (topological order) ──────────────────
|
||||||
PUBLISH_ORDER=(
|
# Finds all non-private packages and sorts by internal dependency count (fewest first)
|
||||||
workflow-protocol
|
mapfile -t PUBLISH_ORDER < <(node -e "
|
||||||
workflow-util
|
const fs = require('fs');
|
||||||
workflow-cas
|
const path = require('path');
|
||||||
workflow-runtime
|
const pkgsDir = path.join('$REPO_ROOT', 'packages');
|
||||||
workflow-reactor
|
const dirs = fs.readdirSync(pkgsDir).filter(d =>
|
||||||
workflow-register
|
fs.existsSync(path.join(pkgsDir, d, 'package.json'))
|
||||||
workflow-execute
|
);
|
||||||
cli-workflow
|
// Collect non-private packages
|
||||||
workflow-util-agent
|
const pkgs = new Map();
|
||||||
workflow-agent-cursor
|
for (const d of dirs) {
|
||||||
workflow-agent-hermes
|
const p = JSON.parse(fs.readFileSync(path.join(pkgsDir, d, 'package.json'), 'utf8'));
|
||||||
workflow-agent-llm
|
if (p.private) continue;
|
||||||
workflow-template-develop
|
const deps = new Set();
|
||||||
workflow-template-solve-issue
|
for (const k of ['dependencies','peerDependencies','devDependencies']) {
|
||||||
)
|
if (!p[k]) continue;
|
||||||
|
for (const n of Object.keys(p[k])) {
|
||||||
|
if (n.startsWith('@uncaged/')) deps.add(n.replace('@uncaged/',''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkgs.set(d, deps);
|
||||||
|
}
|
||||||
|
// Topological sort (Kahn's) — publish dependencies before dependents
|
||||||
|
const inDeg = new Map([...pkgs.keys()].map(k => [k, 0]));
|
||||||
|
for (const [pkg, deps] of pkgs) {
|
||||||
|
for (const dep of deps) {
|
||||||
|
if (pkgs.has(dep)) inDeg.set(pkg, (inDeg.get(pkg) || 0) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const queue = [...inDeg.entries()].filter(([,d]) => d === 0).map(([k]) => k).sort();
|
||||||
|
const order = [];
|
||||||
|
while (queue.length) {
|
||||||
|
const n = queue.shift();
|
||||||
|
order.push(n);
|
||||||
|
for (const [pkg, deps] of pkgs) {
|
||||||
|
if (deps.has(n)) {
|
||||||
|
inDeg.set(pkg, inDeg.get(pkg) - 1);
|
||||||
|
if (inDeg.get(pkg) === 0) queue.push(pkg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Append any remaining (circular or isolated) — should not happen
|
||||||
|
for (const k of pkgs.keys()) { if (!order.includes(k)) order.push(k); }
|
||||||
|
order.forEach(o => console.log(o));
|
||||||
|
")
|
||||||
|
echo "📋 Discovered ${#PUBLISH_ORDER[@]} packages: ${PUBLISH_ORDER[*]}"
|
||||||
|
|
||||||
# ─── Bump version ────────────────────────────────────────────────────────────
|
# ─── Bump version ────────────────────────────────────────────────────────────
|
||||||
echo "🔢 Bumping versions..."
|
echo "🔢 Bumping versions..."
|
||||||
@@ -92,6 +122,13 @@ done
|
|||||||
echo "🔨 Building..."
|
echo "🔨 Building..."
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
|
# ─── Self-test ────────────────────────────────────────────────────────────────
|
||||||
|
echo "🧪 Running tests..."
|
||||||
|
if ! npm test; then
|
||||||
|
echo "❌ Tests failed — aborting publish"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# ─── Publish ─────────────────────────────────────────────────────────────────
|
# ─── Publish ─────────────────────────────────────────────────────────────────
|
||||||
echo "🚀 Publishing..."
|
echo "🚀 Publishing..."
|
||||||
cat > "$REPO_ROOT/.npmrc" <<EOF
|
cat > "$REPO_ROOT/.npmrc" <<EOF
|
||||||
@@ -136,4 +173,39 @@ git commit -m "chore: publish v${VERSION}
|
|||||||
小橘 <xiaoju@shazhou.work>"
|
小橘 <xiaoju@shazhou.work>"
|
||||||
git push
|
git push
|
||||||
|
|
||||||
[[ "$FAIL" -eq 0 ]] && echo "✅ v${VERSION} published" || echo "⚠️ v${VERSION} published with errors"
|
if [[ "$FAIL" -ne 0 ]]; then
|
||||||
|
echo "⚠️ v${VERSION} published with errors"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── Post-publish smoke test ─────────────────────────────────────────────────
|
||||||
|
echo "🔍 Smoke test: installing & verifying published packages..."
|
||||||
|
SMOKE_DIR=$(mktemp -d)
|
||||||
|
trap "rm -rf $SMOKE_DIR" EXIT
|
||||||
|
|
||||||
|
cat > "$SMOKE_DIR/.npmrc" <<EOF
|
||||||
|
@uncaged:registry=${GITEA_NPM_REGISTRY}
|
||||||
|
//${GITEA_NPM_REGISTRY#https://}:_authToken=${GITEA_TOKEN}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Install all published packages in a clean temp dir
|
||||||
|
PKGS_TO_INSTALL=""
|
||||||
|
for pkg_dir in "${PUBLISH_ORDER[@]}"; do
|
||||||
|
PKGS_TO_INSTALL="$PKGS_TO_INSTALL @uncaged/${pkg_dir}@${VERSION}"
|
||||||
|
done
|
||||||
|
|
||||||
|
(cd "$SMOKE_DIR" && npm init -y --silent >/dev/null 2>&1 && npm install $PKGS_TO_INSTALL 2>&1) || {
|
||||||
|
echo "❌ Smoke test failed: could not install packages"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Try importing each package
|
||||||
|
for pkg_dir in "${PUBLISH_ORDER[@]}"; do
|
||||||
|
if ! (cd "$SMOKE_DIR" && node -e "require('@uncaged/${pkg_dir}')" 2>&1); then
|
||||||
|
echo "❌ Smoke test failed: require('@uncaged/${pkg_dir}') threw"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo " ✅ @uncaged/${pkg_dir} — importable"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✅ v${VERSION} published & verified"
|
||||||
|
|||||||
Reference in New Issue
Block a user