Files
mev-beta/orig/tools/bridge/ci_agent_bridge.go
Administrator c54c569f30 refactor: move all remaining files to orig/ directory
Completed clean root directory structure:
- Root now contains only: .git, .env, docs/, orig/
- Moved all remaining files and directories to orig/:
  - Config files (.claude, .dockerignore, .drone.yml, etc.)
  - All .env variants (except active .env)
  - Git config (.gitconfig, .github, .gitignore, etc.)
  - Tool configs (.golangci.yml, .revive.toml, etc.)
  - Documentation (*.md files, @prompts)
  - Build files (Dockerfiles, Makefile, go.mod, go.sum)
  - Docker compose files
  - All source directories (scripts, tests, tools, etc.)
  - Runtime directories (logs, monitoring, reports)
  - Dependency files (node_modules, lib, cache)
  - Special files (--delete)

- Removed empty runtime directories (bin/, data/)

V2 structure is now clean:
- docs/planning/ - V2 planning documents
- orig/ - Complete V1 codebase preserved
- .env - Active environment config (not in git)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 10:53:05 +01:00

176 lines
4.2 KiB
Go

package bridge
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"archive/zip"
)
// SummarizeResult holds artifact summary data
type SummarizeResult struct {
Files []string `json:"files"`
Timestamp time.Time `json:"timestamp"`
}
// SummarizeConfig configures summarization behavior
type SummarizeConfig struct {
ArtifactsDir string
OutputFile string
}
// ApplyPatch applies a patch file to a new branch
func ApplyPatch(op PatchOperation) error {
if op.PatchFile == "" || op.BranchName == "" {
return fmt.Errorf("both --patch and --branch are required")
}
// create new branch
cmd := exec.Command("git", "checkout", "-b", op.BranchName)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("git checkout failed: %s: %w", string(out), err)
}
// apply patch
cmd = exec.Command("git", "apply", op.PatchFile)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("git apply failed: %s: %w", string(out), err)
}
log.Printf("[CI-Agent-Bridge] Patch applied to branch: %s", op.BranchName)
return nil
}
// RevertBranch deletes a branch (hard reset)
func RevertBranch(branch string) error {
if branch == "" {
return fmt.Errorf("--branch is required")
}
// switch to main first
cmd := exec.Command("git", "checkout", "main")
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("git checkout main failed: %s: %w", string(out), err)
}
// delete branch
cmd = exec.Command("git", "branch", "-D", branch)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("git branch delete failed: %s: %w", string(out), err)
}
log.Printf("[CI-Agent-Bridge] Branch reverted: %s", branch)
return nil
}
// RunPodmanCompose executes podman-compose up
func RunPodmanCompose() error {
log.Println("[CI-Agent-Bridge] Starting podman-compose...")
cmd := exec.Command("podman-compose", "up", "-d")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
// ZipDir compresses a directory into a ZIP archive
func ZipDir(srcDir, destZip string) error {
zipFile, err := os.Create(destZip)
if err != nil {
return err
}
defer zipFile.Close()
archive := zip.NewWriter(zipFile)
defer archive.Close()
return filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// skip directories
if info.IsDir() {
return nil
}
// create file in archive
relPath, _ := filepath.Rel(srcDir, path)
zipEntry, err := archive.Create(relPath)
if err != nil {
return err
}
// copy file data
file, err := os.Open(path)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(zipEntry, file)
return err
})
}
// SummarizeArtifacts creates a JSON summary and ZIP of artifacts
func SummarizeArtifacts(cfg SummarizeConfig) error {
var files []string
err := filepath.Walk(cfg.ArtifactsDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
relPath, _ := filepath.Rel(cfg.ArtifactsDir, path)
files = append(files, relPath)
}
return nil
})
if err != nil {
return fmt.Errorf("failed to walk artifacts dir: %w", err)
}
result := SummarizeResult{
Files: files,
Timestamp: time.Now(),
}
// write JSON summary
data, _ := json.MarshalIndent(result, "", " ")
if err := os.WriteFile(cfg.OutputFile, data, 0644); err != nil {
return fmt.Errorf("failed to write summary: %w", err)
}
// create ZIP of artifacts
zipPath := strings.TrimSuffix(cfg.OutputFile, filepath.Ext(cfg.OutputFile)) + ".zip"
if err := ZipDir(cfg.ArtifactsDir, zipPath); err != nil {
return fmt.Errorf("failed to create zip: %w", err)
}
log.Printf("[CI-Agent-Bridge] Artifacts summarized to %s (%d files)", cfg.OutputFile, len(files))
return nil
}
// PatchOperation holds patch application parameters
type PatchOperation struct {
PatchFile string
BranchName string
}
// generateSecureBranchName creates a cryptographically secure random branch name
func generateSecureBranchName() (string, error) {
bytes := make([]byte, 16)
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return "ai/" + hex.EncodeToString(bytes), nil
}