cmd/release/utils/git/manager.go (111 lines of code) (raw):
package git
import (
"bytes"
"fmt"
"log"
"strings"
"time"
"github.com/aws/eks-distro/cmd/release/utils/changetype"
"github.com/aws/eks-distro/cmd/release/utils/values"
)
/*
*
currBranch format example:
1.22-7_development_1654162455
━━┳━━━ ━━━━━┳━━━━━ ━━━━┳━━━━━
Release branch ┃ Current Unix time
and number ┃
ChangeType
(docs, development, production)
*
*/
// Only one Manager can exist due to logic around checked out branches
var alreadyInit = false
type Manager struct {
originalBranch string
changesBranch string
ct changetype.ChangeType
version string
}
// CreateGitManager creates
func CreateGitManager(releaseBranch, number string, ct changetype.ChangeType) (*Manager, error) {
if alreadyInit {
return nil, fmt.Errorf("cannot create more than one GitManager")
}
alreadyInit = true
originalBr, err := showCurrentBranch()
if err != nil {
return &Manager{}, err
}
version := strings.Replace(releaseBranch, "-", ".", 1)
newBranch := fmt.Sprintf("%s-%s_%s_%d", version, number, ct, time.Now().Unix())
if err = checkoutNewBranch(newBranch); err != nil {
return &Manager{}, fmt.Errorf("checking out new branch %s: %w", newBranch, err)
}
log.Printf("Checked out new branch %s off previous branch %s\n", newBranch, originalBr)
return &Manager{
ct: ct,
version: version,
originalBranch: string(originalBr),
changesBranch: newBranch,
}, nil
}
// AddAndCommit adds and commits presumed changes for provided ap. There is no check to see if this file has actually
// changed.
func (gm *Manager) AddAndCommit(ap values.AbsolutePath) error {
return gm.addAndCommit(ap.String(), "Added file "+ap.StripRootDirectory())
}
// AddAndCommitDirectory adds and commits presumed changes for provided nd. There is no check to see if any filed in the
// directory have actually changed. All changes to directory are
func (gm *Manager) AddAndCommitDirectory(nd values.NewDirectory) error {
return gm.addAndCommit(nd.String(), "Added directory "+nd.StripRootDirectory())
}
// DeleteDirectoryAndAbandonAllChanges deletes provided directory and all files in it, checks out the git branch that it
// was on before the creation the Manager, and deletes the branch that was checked out when the Manager was created and
// that all the subsequent changes have been added/committed to.
// IMPORTANT!! Due to the logic around git branches, the Manager will be effectively useless after running this command,
// as the changes branch will be deleted.
func (gm *Manager) DeleteDirectoryAndAbandonAllChanges(nd *values.NewDirectory) error {
if err := gm.currentBranchMustBeChangesBranch(); err != nil {
return fmt.Errorf("checking expected branch before deleting directory: %w", err)
}
if err := nd.RemoveNewDirectory(); err != nil {
return fmt.Errorf("checking expected branch before deleting directory: %w", err)
}
return gm.abandonChangesBranch()
}
// RestoreFileAndAbandonAllChanges restores any changes made to provided filepath, checks out the git branch that it was
// on before the creation the Manager, and deletes the branch that was checked out when the Manager was created and that
// all the subsequent changes have been added/committed to.
// IMPORTANT!! Due to the logic around git branches, the Manager will be effectively useless after running this command,
// as the changes branch will be deleted.
func (gm *Manager) RestoreFileAndAbandonAllChanges(ap values.AbsolutePath) []error {
var errs []error
if err := gm.currentBranchMustBeChangesBranch(); err != nil {
return append(errs, fmt.Errorf("checking expected branch before restoring file: %w", err))
}
if err := restoreStagedFile(ap.String()); err != nil {
errs = append(errs, fmt.Errorf("restoring staged file %s: %w", ap, err))
}
if err := restoreFile(ap.String()); err != nil {
errs = append(errs, fmt.Errorf("restoring file %s: %w", ap, err))
}
if err := gm.abandonChangesBranch(); err != nil {
errs = append(errs, err)
}
return errs
}
// Abandon checks out the git branch that it was on before the creation the Manager, and deletes the branch that was
// checked out when the Manager was created. No changes are dealt with.
// IMPORTANT!! Due to the logic around git branches, the Manager will be effectively useless after running this command,
// as the changes branch will be deleted.
func (gm *Manager) Abandon() error {
if err := gm.currentBranchMustBeChangesBranch(); err != nil {
return fmt.Errorf("checking expected branch before deleting directory: %w", err)
}
return gm.abandonChangesBranch()
}
// currentBranchMustBeChangesBranch returns error the current branch cannot be determined or if the current branch is
// not the changes branch
func (gm *Manager) currentBranchMustBeChangesBranch() error {
currBranch, err := showCurrentBranch()
if err != nil {
return fmt.Errorf("checking if current branch matched expected: %w", err)
}
if !bytes.Equal([]byte(gm.changesBranch), currBranch) {
return fmt.Errorf("expected branch %s does not match the current branch %s", gm.changesBranch, currBranch)
}
return nil
}
// addAndCommit adds and commits presumed changes for provided absolutePath. There is no check to see if this file has
// actually changed.
func (gm *Manager) addAndCommit(absolutePath, commitMessage string) error {
if err := gm.currentBranchMustBeChangesBranch(); err != nil {
return fmt.Errorf("checking expected branch before adding and committing: %w", err)
}
if err := add(absolutePath); err != nil {
return fmt.Errorf("adding %s: %w", absolutePath, err)
}
if err := commit(commitMessage); err != nil {
return fmt.Errorf("committing %s: %w", absolutePath, err)
}
log.Printf("Added and committed %s\n", absolutePath)
return nil
}
// abandonChangesBranch checks out the original branch, deletes the changes branch, and set gm.changesBranch to "".
func (gm *Manager) abandonChangesBranch() error {
if err := checkoutBranch(gm.originalBranch); err != nil {
return fmt.Errorf("abandoning branch while checking out original branch: %w", err)
}
log.Printf("Checked out original branch %s\n", gm.originalBranch)
if err := deleteBranch(gm.changesBranch); err != nil {
return fmt.Errorf("abandoning branch while deleting branch: %w", err)
}
log.Printf("Deleted changes branch %s\n", gm.changesBranch)
gm.changesBranch = ""
return nil
}