Slice 1: build green, MVP core flow
- New agentlib module (gitutil + deployer with NewGo / NewPHP) replaces agent-micro/internal so both agents can share it (Go's internal/ rule was blocking agent-gateway from importing agent-micro's packages). - Migrate agents from legacy github.com/docker/docker/client to the current github.com/moby/moby/client v0.5.0 / moby/moby/api v1.55.0. - Fix compile errors in the original committed code: missing gorilla/websocket import in control-plane/internal/ws/handlers.go, unaliased dockerclient reference, wrong SQLite driver name (sqlite3 -> sqlite), Dialer.Dial 3-return-value mismatch. - scripts/build.sh: Go 1.23 -> 1.24, apk add git, safe.directory for bind-mounted host tree, chmod inside container (host can't chmod files owned by container root). - README and REQUIREMENTS updated to reflect the actual architecture (Go + SQLite, no Spring Boot, moby SDK, per-deploy no image build) with a per-feature status checklist at the end of REQUIREMENTS.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
// Package gitutil wraps the few git operations the agent needs. Credentials
|
||||
// are passed in per-call and never written to disk — every command sets them
|
||||
// via -c credential helpers for the lifetime of the subprocess.
|
||||
package gitutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Creds is a username/password. We pass them through GIT_ASKPASS so they
|
||||
// never appear on the command line or in process listings.
|
||||
type Creds struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// Fetch runs `git fetch --prune origin`. Uses the per-command credential
|
||||
// helper to inject creds without touching the repo's stored config.
|
||||
func Fetch(ctx context.Context, repoDir string, c Creds) (string, error) {
|
||||
return runGit(ctx, repoDir, c, "fetch", "--prune", "origin")
|
||||
}
|
||||
|
||||
// Checkout switches to branch and updates the working tree.
|
||||
func Checkout(ctx context.Context, repoDir, branch string, c Creds) (string, error) {
|
||||
return runGit(ctx, repoDir, c, "checkout", "-f", branch)
|
||||
}
|
||||
|
||||
// Pull fast-forwards the branch to match origin. Safe no-op if up to date.
|
||||
func Pull(ctx context.Context, repoDir string, c Creds) (string, error) {
|
||||
return runGit(ctx, repoDir, c, "pull", "--ff-only")
|
||||
}
|
||||
|
||||
// Probe validates that the credentials work for a given remote. Used at
|
||||
// login. Tries `git ls-remote <origin> HEAD`; succeeds even on an empty repo.
|
||||
func Probe(ctx context.Context, repoDir string, c Creds) error {
|
||||
_, err := runGit(ctx, repoDir, c, "ls-remote", "--heads", "origin", "HEAD")
|
||||
return err
|
||||
}
|
||||
|
||||
// ListBranches lists local branches. Cheap; no network.
|
||||
func ListBranches(ctx context.Context, repoDir string) ([]string, error) {
|
||||
cmd := exec.CommandContext(ctx, "git", "for-each-ref", "--format=%(refname:short)", "refs/heads/")
|
||||
cmd.Dir = repoDir
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("git for-each-ref: %w: %s", err, out)
|
||||
}
|
||||
s := strings.TrimSpace(string(out))
|
||||
if s == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return strings.Split(s, "\n"), nil
|
||||
}
|
||||
|
||||
func runGit(ctx context.Context, repoDir string, c Creds, args ...string) (string, error) {
|
||||
cmd := exec.CommandContext(ctx, "git", args...)
|
||||
cmd.Dir = repoDir
|
||||
// GIT_ASKPASS gives us a per-command credential helper. We just echo the
|
||||
// creds back. The "username" / "password" args are sent to the script's
|
||||
// argv by git.
|
||||
askpass := fmt.Sprintf(`#!/bin/sh
|
||||
case "$1" in
|
||||
username) echo %q ;;
|
||||
password) echo %q ;;
|
||||
esac`, c.Username, c.Password)
|
||||
cmd.Env = append(cmd.Environ(),
|
||||
"GIT_ASKPASS=/dev/stdin",
|
||||
"GIT_TERMINAL_PROMPT=0",
|
||||
)
|
||||
// ponytail: passing askpass via stdin is portable across Linux/macOS.
|
||||
cmd.Stdin = strings.NewReader(askpass)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return string(out), fmt.Errorf("git %s: %w: %s", strings.Join(args, " "), err, out)
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
Reference in New Issue
Block a user