molecule-core/scripts/clone-manifest.sh
devops-engineer 990b4d2eb8
Some checks failed
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 4s
CI / Detect changes (pull_request) Successful in 8s
E2E API Smoke Test / detect-changes (pull_request) Successful in 7s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 8s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 7s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 8s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 8s
cascade-list-drift-gate / check (pull_request) Successful in 15s
CI / Platform (Go) (pull_request) Successful in 6s
CI / Python Lint & Test (pull_request) Successful in 5s
CI / Canvas (Next.js) (pull_request) Successful in 7s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 7s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 7s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 9s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 12s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 37s
CodeQL / Analyze (${{ matrix.language }}) (javascript-typescript) (pull_request) Failing after 1m37s
CodeQL / Analyze (${{ matrix.language }}) (go) (pull_request) Failing after 1m36s
CodeQL / Analyze (${{ matrix.language }}) (python) (pull_request) Failing after 1m38s
fix(post-suspension): redirect clone-manifest to Gitea (Class G #168 followup)
The Class G #168 PR (#40) caught explicit `github.com/Molecule-AI/<repo>`
URL literals in 23 files but missed two indirect forms:

- `scripts/clone-manifest.sh` lines 50,52 had
  `https://github.com/${repo}.git` (the org/repo path is a variable, so the
  Class-G regex `github\.com/Molecule-AI/` didn't match).
- `manifest.json` had `"Molecule-AI/<repo>"` (no `github.com` prefix; the
  prefix gets prepended by the script).

Together these are what `Dockerfile.tenant`'s stage-3 templates RUN
actually fetches. After PR #40 the harness-replays workflow against
staging still fails with `fatal: could not read Username for
'https://github.com'` because the in-image build is the unfixed shell
loop.

This PR:
- scripts/clone-manifest.sh: replaces both clone URLs with
  `https://git.moleculesai.app/${repo}.git`. Anonymous public clones
  work for these repos (verified manually).
- manifest.json: lowercases `Molecule-AI/` to `molecule-ai/` to match
  Gitea's canonical org slug. Gitea is case-insensitive so both work,
  but the lowercase form matches every other URL in the org and is
  what main's clone-manifest.sh (PR #38) already standardises on.

This is the minimum-diff staging fix. Sister #173 already shipped a
more sophisticated version on main (with optional MOLECULE_GITEA_TOKEN
auth + per-build pre-clone). When auto-sync resolves the staging-vs-main
conflict, this minimal version gets superseded by the main version
naturally.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 13:34:53 -07:00

78 lines
2.6 KiB
Bash
Executable File

#!/bin/sh
# clone-manifest.sh — clone all repos listed in manifest.json into their
# target directories. Replaces hardcoded git-clone lines in Dockerfiles.
#
# Usage:
# ./scripts/clone-manifest.sh <manifest.json> <ws-templates-dir> <org-templates-dir> <plugins-dir>
#
# Requires: git, jq (lighter than python3 — ~2MB vs ~50MB in Alpine)
set -euo pipefail
MANIFEST="${1:?Usage: clone-manifest.sh <manifest.json> <ws-dir> <org-dir> <plugins-dir>}"
WS_DIR="${2:?Missing workspace-templates dir}"
ORG_DIR="${3:?Missing org-templates dir}"
PLUGINS_DIR="${4:?Missing plugins dir}"
EXPECTED=0
CLONED=0
clone_category() {
local category="$1"
local target_dir="$2"
mkdir -p "$target_dir"
local count
count=$(jq -r ".${category} | length" "$MANIFEST")
EXPECTED=$((EXPECTED + count))
local i=0
while [ "$i" -lt "$count" ]; do
local name repo ref
name=$(jq -r ".${category}[$i].name" "$MANIFEST")
repo=$(jq -r ".${category}[$i].repo" "$MANIFEST")
ref=$(jq -r ".${category}[$i].ref // \"main\"" "$MANIFEST")
# Idempotent: skip if the target already looks populated. Lets the
# README quickstart rerun setup.sh safely without having to delete
# already-cloned repos. A directory with any entries counts as
# populated; empty dirs reclone (may exist from a prior failed run).
if [ -d "$target_dir/$name" ] && [ -n "$(ls -A "$target_dir/$name" 2>/dev/null || true)" ]; then
echo " skipping $target_dir/$name (already populated)"
CLONED=$((CLONED + 1))
i=$((i + 1))
continue
fi
echo " cloning $repo -> $target_dir/$name (ref=$ref)"
if [ "$ref" = "main" ]; then
git clone --depth=1 -q "https://git.moleculesai.app/${repo}.git" "$target_dir/$name"
else
git clone --depth=1 -q --branch "$ref" "https://git.moleculesai.app/${repo}.git" "$target_dir/$name"
fi
CLONED=$((CLONED + 1))
i=$((i + 1))
done
# Strip .git dirs to save space
find "$target_dir" -name '.git' -type d -exec rm -rf {} + 2>/dev/null || true
}
echo "==> Cloning workspace templates..."
clone_category "workspace_templates" "$WS_DIR"
echo "==> Cloning org templates..."
clone_category "org_templates" "$ORG_DIR"
echo "==> Cloning plugins..."
clone_category "plugins" "$PLUGINS_DIR"
# Verify all repos were cloned
if [ "$CLONED" -ne "$EXPECTED" ]; then
echo "::error::Expected $EXPECTED repos but only cloned $CLONED — some clones failed"
exit 1
fi
echo "==> Done. $CLONED/$EXPECTED repos cloned successfully."