diff --git a/bin/disinto b/bin/disinto index d967c46..4623a3b 100755 --- a/bin/disinto +++ b/bin/disinto @@ -12,7 +12,6 @@ # disinto secrets Manage encrypted secrets # disinto run Run action in ephemeral runner container # disinto ci-logs [--step ] Read CI logs from Woodpecker SQLite -# disinto backup create Export factory state for migration # # Usage: # disinto init https://github.com/user/repo @@ -40,7 +39,6 @@ source "${FACTORY_ROOT}/lib/generators.sh" source "${FACTORY_ROOT}/lib/forge-push.sh" source "${FACTORY_ROOT}/lib/ci-setup.sh" source "${FACTORY_ROOT}/lib/release.sh" -source "${FACTORY_ROOT}/lib/backup.sh" source "${FACTORY_ROOT}/lib/claude-config.sh" source "${FACTORY_ROOT}/lib/disinto/backup.sh" # backup create/import @@ -65,7 +63,6 @@ Usage: disinto hire-an-agent [--formula ] [--local-model ] [--model ] Hire a new agent (create user + .profile repo; re-run to rotate credentials) disinto agent Manage agent state (enable/disable) - disinto backup create Export factory state (issues + ops bundle) disinto edge [options] Manage edge tunnel registrations disinto backup Backup and restore factory state @@ -2910,35 +2907,6 @@ EOF esac } -# ── backup command ──────────────────────────────────────────────────────────── -# Usage: disinto backup [args] -# Subcommands: -# create Create backup of factory state -# import Restore factory state from backup -disinto_backup() { - local subcmd="${1:-}" - shift || true - - case "$subcmd" in - create) - echo "Usage: disinto backup create " >&2 - echo " (Not yet implemented)" >&2 - exit 1 - ;; - import) - backup_import "$@" - ;; - *) - echo "Usage: disinto backup [args]" >&2 - echo "" >&2 - echo "Subcommands:" >&2 - echo " create Create backup of factory state" >&2 - echo " import Restore factory state from backup" >&2 - exit 1 - ;; - esac -} - # ── Main dispatch ──────────────────────────────────────────────────────────── case "${1:-}" in @@ -2955,7 +2923,7 @@ case "${1:-}" in hire-an-agent) shift; disinto_hire_an_agent "$@" ;; agent) shift; disinto_agent "$@" ;; edge) shift; disinto_edge "$@" ;; - backup) shift; disinto_backup "$@" ;; + backup) shift; backup_import "$@" ;; -h|--help) usage ;; *) usage ;; esac diff --git a/lib/backup.sh b/lib/backup.sh deleted file mode 100644 index 8d7a827..0000000 --- a/lib/backup.sh +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env bash -# ============================================================================= -# disinto backup — export factory state for migration -# -# Usage: source this file, then call backup_create -# Requires: FORGE_URL, FORGE_TOKEN, FORGE_REPO, FORGE_OPS_REPO, OPS_REPO_ROOT -# ============================================================================= -set -euo pipefail - -# Fetch all issues (open + closed) for a repo slug and emit the normalized JSON array. -# Usage: _backup_fetch_issues -_backup_fetch_issues() { - local repo_slug="$1" - local api_url="${FORGE_API_BASE}/repos/${repo_slug}" - - local all_issues="[]" - for state in open closed; do - local page=1 - while true; do - local page_items - page_items=$(curl -sf -X GET \ - -H "Authorization: token ${FORGE_TOKEN}" \ - -H "Content-Type: application/json" \ - "${api_url}/issues?state=${state}&type=issues&limit=50&page=${page}") || { - echo "ERROR: failed to fetch ${state} issues from ${repo_slug} (page ${page})" >&2 - return 1 - } - local count - count=$(printf '%s' "$page_items" | jq 'length' 2>/dev/null) || count=0 - [ -z "$count" ] && count=0 - [ "$count" -eq 0 ] && break - all_issues=$(printf '%s\n%s' "$all_issues" "$page_items" | jq -s 'add') - [ "$count" -lt 50 ] && break - page=$((page + 1)) - done - done - - # Normalize to the schema: number, title, body, labels, state - printf '%s' "$all_issues" | jq '[.[] | { - number: .number, - title: .title, - body: .body, - labels: [.labels[]?.name], - state: .state - }] | sort_by(.number)' -} - -# Create a backup tarball of factory state. -# Usage: backup_create -backup_create() { - local outfile="${1:-}" - if [ -z "$outfile" ]; then - echo "Error: output file required" >&2 - echo "Usage: disinto backup create " >&2 - return 1 - fi - - # Resolve to absolute path before cd-ing into tmpdir - case "$outfile" in - /*) ;; - *) outfile="$(pwd)/${outfile}" ;; - esac - - # Validate required env - : "${FORGE_URL:?FORGE_URL must be set}" - : "${FORGE_TOKEN:?FORGE_TOKEN must be set}" - : "${FORGE_REPO:?FORGE_REPO must be set}" - - local forge_ops_repo="${FORGE_OPS_REPO:-${FORGE_REPO}-ops}" - local ops_repo_root="${OPS_REPO_ROOT:-}" - - if [ -z "$ops_repo_root" ] || [ ! -d "$ops_repo_root/.git" ]; then - echo "Error: OPS_REPO_ROOT (${ops_repo_root:-}) is not a valid git repo" >&2 - return 1 - fi - - local tmpdir - tmpdir=$(mktemp -d) - trap 'rm -rf "$tmpdir"' EXIT - - local project_name="${FORGE_REPO##*/}" - - echo "=== disinto backup create ===" - echo "Forge: ${FORGE_URL}" - echo "Repos: ${FORGE_REPO}, ${forge_ops_repo}" - - # ── 1. Export issues ────────────────────────────────────────────────────── - mkdir -p "${tmpdir}/issues" - - echo "Fetching issues for ${FORGE_REPO}..." - _backup_fetch_issues "$FORGE_REPO" > "${tmpdir}/issues/${project_name}.json" - local main_count - main_count=$(jq 'length' "${tmpdir}/issues/${project_name}.json") - echo " ${main_count} issues exported" - - echo "Fetching issues for ${forge_ops_repo}..." - _backup_fetch_issues "$forge_ops_repo" > "${tmpdir}/issues/${project_name}-ops.json" - local ops_count - ops_count=$(jq 'length' "${tmpdir}/issues/${project_name}-ops.json") - echo " ${ops_count} issues exported" - - # ── 2. Git bundle of ops repo ──────────────────────────────────────────── - mkdir -p "${tmpdir}/repos" - - echo "Creating git bundle for ${forge_ops_repo}..." - git -C "$ops_repo_root" bundle create "${tmpdir}/repos/${project_name}-ops.bundle" --all 2>&1 - echo " bundle created ($(du -h "${tmpdir}/repos/${project_name}-ops.bundle" | cut -f1))" - - # ── 3. Metadata ────────────────────────────────────────────────────────── - local created_at - created_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ") - - jq -n \ - --arg created_at "$created_at" \ - --arg source_host "$(hostname)" \ - --argjson schema_version 1 \ - --arg forgejo_url "$FORGE_URL" \ - '{ - created_at: $created_at, - source_host: $source_host, - schema_version: $schema_version, - forgejo_url: $forgejo_url - }' > "${tmpdir}/metadata.json" - - # ── 4. Pack tarball ────────────────────────────────────────────────────── - echo "Creating tarball: ${outfile}" - tar -czf "$outfile" -C "$tmpdir" metadata.json issues repos - local size - size=$(du -h "$outfile" | cut -f1) - echo "=== Backup complete: ${outfile} (${size}) ===" - - # Clean up before returning — the EXIT trap references the local $tmpdir - # which goes out of scope after return, causing 'unbound variable' under set -u. - trap - EXIT - rm -rf "$tmpdir" -}