github.com/charypar/monobuild@v0.0.0-20211122220434-fd884ed50212/cmd/diff.go (about) 1 package cmd 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "log" 9 "os" 10 11 "github.com/charypar/monobuild/cli" 12 "github.com/spf13/cobra" 13 ) 14 15 type diffOptions struct { 16 baseBranch string 17 baseCommit string 18 mainBranch bool 19 rebuildStrong bool 20 dotHighlight bool 21 } 22 23 var diffOpts diffOptions 24 25 var diffCmd = &cobra.Command{ 26 Use: "diff [-]", 27 Short: "Build schedule for components affected by git changes", 28 Long: `Create a build schedule based on git history and dependency graph. 29 Each line in the output is a component and its dependencies. 30 The format of each line is: 31 32 <component>: <dependency>, <dependency>, <dependency>, ... 33 34 Diff can output either the build schedule (using only strong dependencies) or 35 the original dependeny graph (using all dependencies). 36 37 By default changed files are determined from the local git repository. 38 Optionally, they can be provided externaly from stdin, by adding a hypen (-) after 39 the diff command.`, 40 Args: func(cmd *cobra.Command, args []string) error { 41 if len(args) > 1 { 42 return errors.New("Too many arguments") 43 } 44 if len(args) == 1 && args[0] != "-" { 45 return fmt.Errorf("Invalid first argument: %s, only \"-\" is allowed", args[0]) 46 } 47 48 return nil 49 }, 50 Run: diffFn, 51 } 52 53 func init() { 54 rootCmd.AddCommand(diffCmd) 55 56 diffCmd.Flags().StringVar(&diffOpts.baseBranch, "base-branch", "master", "Base branch to use for comparison") 57 diffCmd.Flags().StringVar(&diffOpts.baseCommit, "base-commit", "HEAD^1", "Base commit to compare with (useful in main-brahnch mode when using rebase merging)") 58 diffCmd.Flags().BoolVar(&diffOpts.mainBranch, "main-branch", false, "Run in main branch mode (i.e. only compare with parent commit)") 59 diffCmd.Flags().BoolVar(&diffOpts.rebuildStrong, "rebuild-strong", false, "Include all strong dependencies of affected components") 60 diffCmd.Flags().BoolVar(&commonOpts.printDependencies, "dependencies", false, "Ouput the dependencies, not the build schedule") 61 diffCmd.Flags().BoolVar(&commonOpts.dotFormat, "dot", false, "Print in DOT format for GraphViz") 62 diffCmd.Flags().BoolVar(&commonOpts.printFull, "full", false, "Print the full dependency graph including strengths") 63 } 64 65 func diffFn(cmd *cobra.Command, args []string) { 66 // first we tediously process the CLI flags 67 var branchMode cli.DiffMode 68 changedFiles := []string{} 69 70 if len(args) > 0 && args[0] == "-" { 71 branchMode = cli.Direct 72 73 // Read stdin into []string 74 scanner := bufio.NewScanner(os.Stdin) 75 for scanner.Scan() { 76 changedFiles = append(changedFiles, scanner.Text()) 77 } 78 79 } else if diffOpts.mainBranch { 80 branchMode = cli.MainBranch 81 } else { 82 branchMode = cli.FeatureBranch 83 } 84 85 var format cli.OutputFormat 86 if commonOpts.dotFormat { 87 format = cli.Dot 88 } else { 89 format = cli.Text 90 } 91 92 diffContext := cli.DiffContext{ 93 Mode: branchMode, 94 BaseBranch: diffOpts.baseBranch, 95 BaseCommit: diffOpts.baseCommit, 96 ChangedFiles: changedFiles, 97 } 98 scope := cli.Scope{Scope: commonOpts.scope, TopLevel: commonOpts.topLevel} 99 100 var outType cli.OutputType 101 if commonOpts.printFull { 102 outType = cli.Full 103 } else if commonOpts.printDependencies { 104 outType = cli.Dependencies 105 } else { 106 outType = cli.Schedule 107 } 108 109 outputOpts := cli.OutputOptions{Format: format, Type: outType} 110 111 repoManifest := "" 112 if len(commonOpts.repoManifestFile) > 0 { 113 bytes, err := ioutil.ReadFile(commonOpts.repoManifestFile) 114 if err != nil { 115 log.Fatal(err) 116 } 117 118 repoManifest = string(bytes) 119 } 120 121 // run the CLI command 122 dependencies, schedule, impacted, err := cli.Diff(commonOpts.dependencyFilesGlob, diffContext, scope, diffOpts.rebuildStrong, repoManifest) 123 if err != nil { 124 log.Fatal(err) 125 } 126 127 fmt.Print(cli.Format(dependencies, schedule, impacted, outputOpts)) 128 }