forge/doClean.go

214 lines
5.7 KiB
Go

// 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"
"path/filepath"
"go.wit.com/lib/protobuf/gitpb"
"go.wit.com/log"
)
// reverts all repos back to the original master branches
// automatically deletes local devel and user branches
func doClean() error {
// fix this to work, then delete all the other options for "forge clean'
if err := doAllCheckoutMaster(); err != nil {
// badExit(err)
}
all := me.forge.Repos.SortByFullPath()
for all.Scan() {
repo := all.Next()
if repo.GetCurrentBranchName() != repo.GetMasterBranchName() {
continue
}
if repo.IsDirty() {
continue
}
if repo.GetTargetVersion() != "" {
repo.SetTargetVersion("")
configSave = true
}
// try to delete user
if err := doCleanUserRepo(repo); err != nil {
log.Info(repo.GetGoPath(), err)
}
// try to delete devel
doRepoCleanDevel(repo)
}
log.Info("finished attempt at cleaning devel branches")
return nil
}
/*
func doesLocalBranchExist(repo *gitpb.Repo, branch string) bool {
return repo.Exists(filepath.Join(".git/refs/heads", branch))
}
*/
func doRepoCleanDevel(repo *gitpb.Repo) error {
if !repo.IsLocalBranch(repo.GetDevelBranchName()) {
// there is no local branch named 'devel'
return nil
}
if repo.GetCurrentBranchName() != repo.GetMasterBranchName() {
return log.Errorf("%s not on master branch:", repo.GetFullPath())
}
if repo.IsDirty() {
return log.Errorf("%s is dirty:", repo.GetFullPath())
}
if err := justDeleteTheDevelBranchAlready(repo); err != nil {
log.Info("justDeleteTheDevel() err", repo.GetGoPath(), err)
return err
}
return nil
}
func doCleanDevel() error {
var total int
var count int
all := me.forge.Repos.SortByFullPath()
for all.Scan() {
repo := all.Next()
total += 1
if !repo.IsLocalBranch(repo.GetDevelBranchName()) {
// there is no local branch named 'devel'
continue
}
if repo.GetCurrentBranchName() != repo.GetMasterBranchName() {
log.Info("Repo not on master branch:", repo.GetGoPath())
continue
}
if repo.IsDirty() {
log.Info("Repo is dirty:", repo.GetGoPath())
continue
}
count += 1
if err := justDeleteTheDevelBranchAlready(repo); err != nil {
log.Info("justDeleteTheDevel() err", repo.GetGoPath(), err)
}
}
log.Info("")
log.Printf("attempted cleaning %d devel branches of %d total branches\n", count, total)
return nil
}
// removes all local branches
func doCleanUserRepo(repo *gitpb.Repo) error {
if repo.IsDirty() {
return nil
}
bruser := repo.GetUserBranchName()
brdevel := repo.GetDevelBranchName()
if repo.IsBranchRemote(bruser) {
log.Info("forge is designed to always have local only user branches", bruser)
return fmt.Errorf("forge is designed to always have local only user branches")
}
if !repo.IsLocalBranch(bruser) {
// there is no local user branch
return nil
}
// will you loose work if you delete your user branch?
// if DevelBranchExists()
// then if UserBranchCommits exist in DevelBranch
// DeleteUserBranch is safe
if repo.IsLocalBranch(brdevel) {
b1 := repo.CountDiffObjects(bruser, "refs/heads/"+brdevel) // should be zero
if b1 == 0 {
// every user branch exists in devel. delete user branch
cmd := []string{"git", "branch", "-D", bruser}
log.Info("USER IS IN DEVEL", repo.GetGoPath(), cmd)
err := repo.RunVerbose(cmd)
return err
}
}
brmaster := repo.GetMasterBranchName()
// will you loose work if you delete your user branch?
// if master branch exists()
// then if all user commits exist in master
// delete user branch is safe
if repo.IsLocalBranch(brmaster) {
b1 := repo.CountDiffObjects(bruser, "refs/heads/"+brmaster) // should be zero
if b1 == 0 {
cmd := []string{"git", "branch", "-D", bruser}
log.Info("USER IS IN DEVEL", repo.GetGoPath(), cmd)
err := repo.RunVerbose(cmd)
return err
}
}
return fmt.Errorf("%s branch has unique commits", bruser)
}
// hack to cleanup release versioning info
func doCleanPub() error {
total := 0
all := me.forge.Repos.SortByFullPath()
for all.Scan() {
repo := all.Next()
if repo.GetTargetVersion() != "" {
repo.SetTargetVersion("")
configSave = true
total += 1
}
}
log.Printf("clearing %d total repos\n", total)
return nil
}
// if you call this, there is no going back. no checks anymore. nothing
// it deletes the 'devel' branch. git branch -D "devel". END OF STORY
func justDeleteTheDevelBranchAlready(repo *gitpb.Repo) error {
branch := repo.GetDevelBranchName()
remote := filepath.Join("origin", branch)
if me.forge.Config.IsReadOnly(repo.GetGoPath()) {
if repo.IsDevelRemote() {
// just make sure the remote & local branches are the same
return repo.DeleteLocalDevelBranch()
}
}
// check against remote if it exists
if repo.IsDevelRemote() {
b1 := repo.CountDiffObjects(branch, remote) // should be zero
if b1 == 0 {
cmd := []string{"git", "branch", "-D", repo.GetDevelBranchName()}
log.Info("DEVEL IS IN REMOTE", repo.GetGoPath(), cmd)
err := repo.RunVerbose(cmd)
return err
}
cmd := []string{"git", "push"}
log.Info("DEVEL LOCAL NEEDS GIT PUSH TO REMOTE", repo.GetGoPath(), cmd)
err := repo.RunVerbose(cmd)
return err
}
// remote doesn't exist, check against master
master := repo.GetMasterBranchName()
b1 := repo.CountDiffObjects(branch, "refs/heads/"+master) // should be zero
if b1 == 0 {
cmd := []string{"git", "branch", "-D", repo.GetDevelBranchName()}
log.Info("DEVEL IS IN REMOTE", repo.GetGoPath(), cmd)
err := repo.RunVerbose(cmd)
return err
}
cmd := []string{"git", "merge something somehow"}
log.Info("DEVEL LOCAL NEEDS GIT MERGE TO MASTER", repo.GetGoPath(), cmd, b1)
// _, err := repo.RunVerbose(cmd)
return nil
}