Skip to content

repo bootstrap exits 0 when a bootstrap command fails #50

Description

@Th3Mouk

Summary

maestro repo bootstrap exits 0 when a bootstrap command fails. The failure
is detected and reported correctly (BOOTSTRAP_COMMAND_FAILED, status: "warning"),
but the process exit code does not reflect it, so maestro repo bootstrap && <next step>
proceeds on a workspace whose dependencies were never installed, and CI goes green.

Related, same report: the per-repository row says state: executed for a command
that failed. There is no per-repository failure state, so the table alone reads as
a success.

I hit this for real: one of five repositories failed its bootstrap on a network
timeout while the other four succeeded. The command exited 0 and the summary line
said warning, so nothing downstream noticed the repository had no dependencies.

Reproduction

# a local origin, so the repro needs no network
mkdir -p /tmp/mrepro/origin /tmp/mrepro/seed
git init -q --bare /tmp/mrepro/origin/demo.git
cd /tmp/mrepro/seed
git init -q -b main .
echo '{}' > package.json
git add -A && git -c user.email=t@t -c user.name=t commit -qm init
git remote add origin /tmp/mrepro/origin/demo.git && git push -q origin main

# a workspace whose single repository has a bootstrap command that fails
cd /tmp/mrepro && maestro init ws
cat > /tmp/mrepro/ws/maestro.yaml <<'YAML'
apiVersion: maestro/v1
kind: Workspace
metadata:
  name: repro
spec:
  repositories:
    - name: demo
      remote: /tmp/mrepro/origin/demo.git
      branch: main
      bootstrap:
        strategy: manual
        commands:
          - sh -c 'echo BOOTSTRAP_RAN; exit 3'
YAML

cd /tmp/mrepro/ws
maestro workspace install --workspace .
maestro repo bootstrap --workspace . --format human; echo "EXIT=$?"

Observed

BOOTSTRAP_RAN
repo bootstrap: warning (1 executed, 0 skipped, 1 issues)
repro
┌────────────────────────┬────────────┬──────────────────────────────────────────┐
│ Repository             │ State      │ Commands                                 │
├────────────────────────┼────────────┼──────────────────────────────────────────┤
│ demo                   │ executed   │ sh -c 'echo BOOTSTRAP_RAN; exit 3'       │
└────────────────────────┴────────────┴──────────────────────────────────────────┘
Issues:
  - BOOTSTRAP_COMMAND_FAILED: Bootstrap command failed for demo (…): Command failed with exit code 3: …
EXIT=0

--format json agrees on the content and also exits 0:

{
  "data": {
    "status": "warning",
    "repositories": [{ "commands": ["sh -c 'echo BOOTSTRAP_RAN; exit 3'"], "name": "demo", "skipped": false }],
    "issues": [{ "code": "BOOTSTRAP_COMMAND_FAILED", "message": "… exit code 3 …", "path": "…/repos/demo" }]
  },
  "schemaVersion": 1
}

Expected

A non-zero exit when a bootstrap command fails, and a per-repository state that
distinguishes a failed command from a successful one (failed rather than
executed).

Why this one differs from the documented convention

docs/cli/commands.md deliberately says:

Branch on report status without relying on exit codes

That reads right for the reporting commands — doctor, repo list — where a
finding is information and exit 0 is a fine contract. repo bootstrap is not a
reporting command: it runs commands, and here the report is not describing state it
observed, it is describing an action it was asked to perform and could not. That is
the case an exit code exists for, and it is the one that composes with &&, set -e
and CI without every caller having to pipe through jq.

Verified for contrast: maestro workspace doctor on this same workspace exits 0 with
ok (0 issues) — so today the two are indistinguishable to a caller.

If the convention should hold uniformly, an opt-in (--fail-on-issues, or a
documented note under repo bootstrap that its exit code is not a success signal)
would be enough to make the trap visible.

Environment

  • Maestro 0.2.0 (Homebrew, latest release at time of writing)
  • macOS 25.6.0, arm64

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions