github.com/charypar/monobuild@v0.0.0-20211122220434-fd884ed50212/diff/diff.go (about)

     1  package diff
     2  
     3  import (
     4  	"fmt"
     5  	"os/exec"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/charypar/monobuild/graph"
    10  )
    11  
    12  // BranchMode is the diff mode based on the kind of branch, either Feature or Main
    13  type BranchMode int
    14  
    15  // Feature is a feature branch mode
    16  var Feature BranchMode = 1
    17  
    18  // Main is a main branch mode
    19  var Main BranchMode = 2
    20  
    21  // Mode holds options for the Diff command
    22  type Mode struct {
    23  	Mode       BranchMode
    24  	BaseBranch string
    25  	BaseCommit string
    26  }
    27  
    28  func diffBase(mode Mode) (string, error) {
    29  	if mode.Mode == Main {
    30  		return mode.BaseCommit, nil
    31  	}
    32  
    33  	gitMergeBase := exec.Command("git", "merge-base", mode.BaseBranch, "HEAD")
    34  	mergeBase, err := gitMergeBase.Output()
    35  	if err != nil {
    36  		if ee, ok := err.(*exec.ExitError); ok {
    37  			return "", fmt.Errorf("cannot find merge base with branch '%s': %s", mode.BaseBranch, ee.Stderr)
    38  		} else {
    39  			return "", fmt.Errorf("cannot find merge base with branch '%s': %s", mode.BaseBranch, err)
    40  		}
    41  	}
    42  
    43  	return strings.TrimRight(string(mergeBase), "\n"), nil
    44  }
    45  
    46  // ChangedFiles uses git to determine the list of files that changed for
    47  // the current revision.
    48  // It can operate in a normal (branch) mode, where it compares to a 'baseBranch'
    49  // or a 'mainBranch' mode, where it compares to the previous revision or a 'baseCommit'
    50  func ChangedFiles(mode Mode) ([]string, error) {
    51  	base, err := diffBase(mode)
    52  	if err != nil {
    53  		return []string{}, err
    54  	}
    55  
    56  	gitDiff := exec.Command("git", "diff", "--no-commit-id", "--name-only", "-r", base)
    57  
    58  	gitOut, err := gitDiff.Output()
    59  	if err != nil {
    60  		if ee, ok := err.(*exec.ExitError); ok {
    61  			return []string{}, fmt.Errorf("cannot find changed files:\n%s", ee.Stderr)
    62  		} else {
    63  			return []string{}, fmt.Errorf("cannot find changed files:\n%s", err)
    64  		}
    65  	}
    66  
    67  	changed := strings.Split(strings.TrimRight(string(gitOut), "\n"), "\n")
    68  	return changed, nil
    69  }
    70  
    71  // Impacted calculates the list of changes impacted by a change
    72  func Impacted(changedComponents []string, dependencies graph.Graph) []string {
    73  	impactGraph := dependencies.Reverse()
    74  	impacted := impactGraph.Descendants(changedComponents)
    75  
    76  	result := append(impacted, changedComponents...)
    77  	sort.Strings(result)
    78  
    79  	return result
    80  }