// Copyright 2017-2025 WIT.COM Inc. All rights reserved. // Use of this source code is governed by the GPL 3.0 package main import ( "fmt" "strings" "go.wit.com/lib/protobuf/forgepb" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) func doDeleteUser() (string, error) { found := gitpb.NewRepos() setForgeMode(forgepb.ForgeMode_MASTER) for repo := range me.forge.Repos.IterByNamespace() { uremoteref := repo.GetRemoteTag(repo.GetUserBranchName()) if uremoteref == nil { localRef := repo.IsBranchLocal(repo.GetUserBranchName()) if localRef == nil { // user branches don't exist continue } log.Info("branch is only local") if err, _ := doFixDeleteLocalUserByDevel(repo, localRef); err == nil { // must have deleted it by devel continue } if err, _ := doFixDeleteLocalUserByMaster(repo, localRef); err == nil { // must have deleted it by master continue } continue } found.Repos = append(found.Repos, repo) if !repo.IsMasterBranch() { if argv.Fix { log.Info("you just be in the master branch to run --fix") repo.State = "needs master branch" continue } } doFixDeleteUserBranches(repo, uremoteref) } me.forge.PrintHumanTable(found) return "TODO: CHECK git patchId to verify these", nil } func doFixPrint(s string, path string, cmd string) { log.Printf("%-13.13s %-55.55s %s\n", s, path, cmd) } func doFixDeleteUserBranches(repo *gitpb.Repo, remoteRef *gitpb.GitTag) *notesList { // log.Info("delete remote user", repo.FullPath) localTag := repo.IsBranchLocal(repo.GetUserBranchName()) if localTag != nil { // log.Info("THERE IS local user", repo.FullPath, localTag.Refname) doFixPrint("LOCAL USER", repo.FullPath, localTag.Refname+" local branch exists") err, notes := doFixDeleteUserLocalBranch(repo, remoteRef, localTag) if err != nil { log.Printf("%-13.13s %-55.55s %v noteslen(%d)\n", "need --fix", repo.FullPath, err, len(notes.all)) } } err, notes := doFixDeleteRemoteUserBranch(repo, remoteRef) if err != nil { log.Printf("%-13.13s %-55.55s %v noteslen(%d)\n", "need --fix", repo.FullPath, err, len(notes.all)) } return notes } // notes.addNote("SAFE", repo, remoteUser, line) func (notes *notesList) addNote(note string, repo *gitpb.Repo, ref *gitpb.GitTag, cmd []string, line string) { newnote := new(DeleteBranchNotes) newnote.Note = note newnote.Refname = ref.Refname newnote.Fullpath = repo.FullPath newnote.Cmd = cmd parts := strings.Split(line, "%00") // git log doesn't actually convert %00 to NULL if len(parts) != 4 { log.Info("len", len(parts)) panic("nope") } newnote.H = parts[0] newnote.Ae = parts[1] newnote.As = parts[2] newnote.S = parts[3] // newnote.Hash = parts[0] log.Printf("%-5.5s %7.7s %-55.55s %v\n", note, newnote.H, newnote.Fullpath, cmd) notes.all = append(notes.all, newnote) } type notesList struct { all []*DeleteBranchNotes } type DeleteBranchNotes struct { Note string Refname string Fullpath string Cmd []string // git log variable names H string S string Ae string As string } // git branch -D refs/heads/jcarr // git update-ref -d refs/heads/jcarr func doFixDeleteUserLocalBranch(repo *gitpb.Repo, remoteRef *gitpb.GitTag, localRef *gitpb.GitTag) (error, *notesList) { notes := new(notesList) // get local user, remote user & local devel branches dref := repo.GetLocalDevelRef() localUser := repo.NewCompareRef(localRef) remoteUser := repo.NewCompareRef(remoteRef) localDevel := repo.NewCompareRef(dref) // Is the localUser completely inside the remoteUser branch? hashok, hashbad, cmd1, cmd2, err := remoteUser.CompareBranch(localUser) for _, line := range hashok { notes.addNote("OK", repo, remoteUser.GetRef(), cmd1, line) } for _, line := range hashbad { notes.addNote("BAD", repo, localUser.GetRef(), cmd2, line) } if err != nil { log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd1) log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd2) return err, notes } if len(hashbad) == 0 { // git update-ref -d refs/heads/jcarr cmd := []string{"git", "update-ref", "-d", localUser.GetRefname()} log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd1, "") log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd2, "") log.Printf("%-13.13s %-55.55s %v %s\n", "SAFE TO DELETE", repo.FullPath, cmd, "add --fix") if argv.Fix { err := repo.RunVerbose(cmd) if err != nil { log.Info(localUser.GetRefname(), repo.FullPath) s := "local user branch could not be deleted" me.sh.BadExit(s, err) } return nil, notes } return ErrorNeedArgvFix, notes } // Is the localUser completely inside the localDevel branch? hashok, hashbad, cmd1, cmd2, err = localDevel.CompareBranch(localUser) for _, line := range hashok { notes.addNote("OK", repo, localDevel.GetRef(), cmd1, line) } for _, line := range hashbad { notes.addNote("BAD", repo, localUser.GetRef(), cmd2, line) } // git update-ref -d refs/heads/jcarr if err != nil { log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd1) log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd2) return err, notes } if len(hashbad) == 0 { cmd := []string{"git", "update-ref", "-d", localUser.GetRefname()} log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd1, "") log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd2, "") log.Printf("%-13.13s %-55.55s %v %s\n", "SAFE TO DELETE", repo.FullPath, cmd, "add --fix") if argv.Fix { err := repo.RunVerbose(cmd) if err != nil { log.Info(localUser.GetRefname(), repo.FullPath) s := "local user branch could not be deleted" me.sh.BadExit(s, err) } } return ErrorNeedArgvFix, notes } return log.Errorf("NOT SAFE"), notes } // git push --delete origin jcarr // git push origin :refs/remotes/origin/jcarr func doFixDeleteRemoteUserBranch(repo *gitpb.Repo, remoteRef *gitpb.GitTag) (error, *notesList) { notes := new(notesList) // get remote user & local devel branches remoteUser := repo.NewCompareRef(remoteRef) dref := repo.GetLocalDevelRef() localDevel := repo.NewCompareRef(dref) // Is the remoteUser completely inside the localDevel branch? hashok, hashbad, cmd1, cmd2, err := localDevel.CompareBranch(remoteUser) for _, line := range hashok { notes.addNote("OK", repo, localDevel.GetRef(), cmd1, line) } for _, line := range hashbad { notes.addNote("BAD", repo, remoteUser.GetRef(), cmd2, line) } // git update-ref -d refs/heads/jcarr if err != nil { log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd1) log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd2) return err, notes } if len(hashbad) == 0 { cmd := []string{"git", "push", "origin", ":" + remoteUser.GetRefname()} log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd1, "") log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd2, "") log.Printf("%-13.13s %-55.55s %v %s\n", "SAFE TO DELETE", repo.FullPath, cmd, "add --fix") if argv.Fix { err := repo.RunVerbose(cmd) if err != nil { log.Info(remoteUser.GetRefname(), repo.FullPath) s := "remote user branch could not be deleted" me.sh.BadExit(s, err) } } return ErrorNeedArgvFix, notes } return log.Errorf("NOT SAFE"), notes } // deletes local user branch if it's entirely in devel func doFixDeleteLocalUserByDevel(repo *gitpb.Repo, localRef *gitpb.GitTag) (error, *notesList) { notes := new(notesList) localUser := repo.NewCompareRef(localRef) dref := repo.GetLocalDevelRef() if dref == nil { return fmt.Errorf("no local devel"), notes } localDevel := repo.NewCompareRef(dref) // Is the localUser completely inside the localDevel branch? hashok, hashbad, cmd1, cmd2, err := localDevel.CompareBranch(localUser) for _, line := range hashok { notes.addNote("OK", repo, localDevel.GetRef(), cmd1, line) } for _, line := range hashbad { notes.addNote("BAD", repo, localUser.GetRef(), cmd2, line) } if err != nil { log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd1) log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd2) return err, notes } if len(hashbad) == 0 { cmd := []string{"git", "update-ref", "-d", localUser.GetRefname()} log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd1, "") log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd2, "") log.Printf("%-13.13s %-55.55s %v %s\n", "SAFE TO DELETE", repo.FullPath, cmd, "add --fix") if argv.Fix { err := repo.RunVerbose(cmd) if err != nil { log.Info(localUser.GetRefname(), repo.FullPath) s := "local user branch could not be deleted" me.sh.BadExit(s, err) } } return ErrorNeedArgvFix, notes } return log.Errorf("NOT SAFE"), notes } // deletes local user branch if it's entirely in master func doFixDeleteLocalUserByMaster(repo *gitpb.Repo, localRef *gitpb.GitTag) (error, *notesList) { notes := new(notesList) localUser := repo.NewCompareRef(localRef) mref := repo.GetLocalMasterRef() if mref == nil { return fmt.Errorf("no local master"), notes } localMaster := repo.NewCompareRef(mref) // Is the localUser completely inside the localMaster branch? hashok, hashbad, cmd1, cmd2, err := localMaster.CompareBranch(localUser) for _, line := range hashok { notes.addNote("OK", repo, localMaster.GetRef(), cmd1, line) } for _, line := range hashbad { notes.addNote("BAD", repo, localUser.GetRef(), cmd2, line) } if err != nil { log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd1) log.Printf("%-13.13s %-55.55s err='%v' %s %v\n", "CMD ERR", repo.FullPath, err, "NOT SAFE TO DELETE. Reload()?", cmd2) return err, notes } if len(hashbad) == 0 { cmd := []string{"git", "update-ref", "-d", localUser.GetRefname()} log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd1, "") log.Printf("%-13.13s %-55.55s %v %s\n", "CMD OK", repo.FullPath, cmd2, "") log.Printf("%-13.13s %-55.55s %v %s\n", "SAFE TO DELETE", repo.FullPath, cmd, "add --fix") if argv.Fix { err := repo.RunVerbose(cmd) if err != nil { log.Info(localUser.GetRefname(), repo.FullPath) s := "local user branch could not be deleted" me.sh.BadExit(s, err) } } return ErrorNeedArgvFix, notes } return log.Errorf("NOT SAFE"), notes }