refactor: split each run business

main
sudo pacman -Syu 2022-07-22 22:40:39 +07:00
parent fa101cad93
commit febe519d27
No known key found for this signature in database
GPG Key ID: D6CB5C6C567C47B0
2 changed files with 151 additions and 70 deletions

View File

@ -17,6 +17,9 @@ import (
const ( const (
gitDirectory = ".git" gitDirectory = ".git"
vendorDirectory = "vendor"
goModFile = "go.mod"
goSumFile = "go.sum"
) )
var ( var (
@ -34,11 +37,53 @@ type Module struct {
func (a *action) Run(c *cli.Context) error { func (a *action) Run(c *cli.Context) error {
a.getFlags(c) a.getFlags(c)
mapImportedModules, err := a.runGetImportedModules(c)
if err != nil {
return err
}
// Check vendor exist to run go mod vendor
existVendor := false
if _, err := os.Stat(vendorDirectory); err == nil {
existVendor = true
}
depsFileStr, err := a.runReadDepsFile(c)
if err != nil {
return err
}
if depsFileStr == "" {
return nil
}
// Read deps file line by line to upgrade
successUpgradedModules := make([]Module, 0, 100)
modulePaths := strings.Split(depsFileStr, "\n")
for _, modulePath := range modulePaths {
successUpgradedModules, err = a.runUpgradeModule(c, mapImportedModules, successUpgradedModules, modulePath)
if err != nil {
color.PrintAppError(name, err.Error())
}
}
if err := a.runGoMod(c, existVendor); err != nil {
return err
}
if err := a.runGitCommit(c, successUpgradedModules, existVendor); err != nil {
return err
}
return nil
}
func (a *action) runGetImportedModules(c *cli.Context) (map[string]struct{}, error) {
// Get all imported modules // Get all imported modules
goListAllArgs := []string{"list", "-m", "-json", "all"} goListAllArgs := []string{"list", "-m", "-json", "all"}
goOutput, err := exec.CommandContext(c.Context, "go", goListAllArgs...).CombinedOutput() goOutput, err := exec.CommandContext(c.Context, "go", goListAllArgs...).CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goListAllArgs, " "), err) return nil, fmt.Errorf("failed to run go %+v: %w", strings.Join(goListAllArgs, " "), err)
} }
// goAllOutput is like {...}\n{...}\n{...} // goAllOutput is like {...}\n{...}\n{...}
@ -49,7 +94,7 @@ func (a *action) Run(c *cli.Context) error {
importedModules := make([]Module, 0, 100) importedModules := make([]Module, 0, 100)
if err := json.Unmarshal([]byte(goOutputStr), &importedModules); err != nil { if err := json.Unmarshal([]byte(goOutputStr), &importedModules); err != nil {
return fmt.Errorf("failed to json unmarshal: %w", err) return nil, fmt.Errorf("failed to json unmarshal: %w", err)
} }
a.log("go output: %s", string(goOutput)) a.log("go output: %s", string(goOutput))
@ -59,23 +104,27 @@ func (a *action) Run(c *cli.Context) error {
} }
a.log("imported modules: %+v\n", importedModules) a.log("imported modules: %+v\n", importedModules)
return mapImportedModules, nil
}
func (a *action) runReadDepsFile(c *cli.Context) (string, error) {
// Try to parse url first // Try to parse url first
var depsFileStr string var depsFileStr string
depsFileURL, err := url.Parse(a.flags.depsFile) depsFileURL, err := url.Parse(a.flags.depsFile)
if err == nil { if err == nil {
httpRsp, err := http.Get(depsFileURL.String()) httpRsp, err := http.Get(depsFileURL.String())
if err != nil { if err != nil {
return fmt.Errorf("failed to http get %s: %w", depsFileURL.String(), err) return "", fmt.Errorf("failed to http get %s: %w", depsFileURL.String(), err)
} }
defer httpRsp.Body.Close() defer httpRsp.Body.Close()
if httpRsp.StatusCode != http.StatusOK { if httpRsp.StatusCode != http.StatusOK {
return fmt.Errorf("http status code not ok %d: %w", httpRsp.StatusCode, ErrFailedStatusCode) return "", fmt.Errorf("http status code not ok %d: %w", httpRsp.StatusCode, ErrFailedStatusCode)
} }
depsFileBytes, err := io.ReadAll(httpRsp.Body) depsFileBytes, err := io.ReadAll(httpRsp.Body)
if err != nil { if err != nil {
return fmt.Errorf("failed to read http response body: %w", err) return "", fmt.Errorf("failed to read http response body: %w", err)
} }
depsFileStr = string(depsFileBytes) depsFileStr = string(depsFileBytes)
@ -87,78 +136,103 @@ func (a *action) Run(c *cli.Context) error {
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
color.PrintAppWarning(name, fmt.Sprintf("deps file [%s] not found", a.flags.depsFile)) color.PrintAppWarning(name, fmt.Sprintf("deps file [%s] not found", a.flags.depsFile))
return nil return "", nil
} }
return fmt.Errorf("failed to read file %s: %w", a.flags.depsFile, err) return "", fmt.Errorf("failed to read file %s: %w", a.flags.depsFile, err)
} }
depsFileStr = strings.TrimSpace(string(depsFileBytes)) depsFileStr = strings.TrimSpace(string(depsFileBytes))
} }
// Read deps file line by line to upgrade return depsFileStr, nil
successUpgradeModules := make([]Module, 0, 100)
lines := strings.Split(depsFileStr, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line == "" {
continue
} }
a.log("line: %s", line)
func (a *action) runUpgradeModule(
c *cli.Context,
mapImportedModules map[string]struct{},
successUpgradedModules []Module,
modulePath string,
) ([]Module, error) {
modulePath = strings.TrimSpace(modulePath)
if modulePath == "" {
return successUpgradedModules, nil
}
a.log("line: %s", modulePath)
// Check if line is imported module, otherwise skip // Check if line is imported module, otherwise skip
if _, ok := mapImportedModules[line]; !ok { if _, ok := mapImportedModules[modulePath]; !ok {
a.log("%s is not imported module", line) a.log("%s is not imported module", modulePath)
continue return successUpgradedModules, nil
} }
// Get module latest version // Get module latest version
goListArgs := []string{"list", "-m", "-u", "-json", line} goListArgs := []string{"list", "-m", "-u", "-json", modulePath}
goOutput, err = exec.CommandContext(c.Context, "go", goListArgs...).CombinedOutput() goOutput, err := exec.CommandContext(c.Context, "go", goListArgs...).CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goListArgs, " "), err) return successUpgradedModules, fmt.Errorf("failed to run go %+v: %w", strings.Join(goListArgs, " "), err)
} }
a.log("go output: %s", string(goOutput)) a.log("go output: %s", string(goOutput))
module := Module{} module := Module{}
if err := json.Unmarshal(goOutput, &module); err != nil { if err := json.Unmarshal(goOutput, &module); err != nil {
return fmt.Errorf("failed to json unmarshal: %w", err) return successUpgradedModules, fmt.Errorf("failed to json unmarshal: %w", err)
} }
a.log("module: %+v", module) a.log("module: %+v", module)
if module.Update == nil { if module.Update == nil {
color.PrintAppOK(name, fmt.Sprintf("You already have latest [%s] version [%s]", module.Path, module.Version)) color.PrintAppOK(name, fmt.Sprintf("You already have latest [%s] version [%s]", module.Path, module.Version))
continue return successUpgradedModules, nil
} }
// Upgrade module // Upgrade module
if a.flags.dryRun { if a.flags.dryRun {
color.PrintAppOK(name, fmt.Sprintf("Will upgrade [%s] version [%s] to [%s]", module.Path, module.Version, module.Update.Version)) color.PrintAppOK(name, fmt.Sprintf("Will upgrade [%s] version [%s] to [%s]", module.Path, module.Version, module.Update.Version))
continue return successUpgradedModules, nil
} }
goGetArgs := []string{"get", "-d", line + "@" + module.Update.Version} goGetArgs := []string{"get", "-d", modulePath + "@" + module.Update.Version}
goOutput, err = exec.CommandContext(c.Context, "go", goGetArgs...).CombinedOutput() goOutput, err = exec.CommandContext(c.Context, "go", goGetArgs...).CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goGetArgs, " "), err) return successUpgradedModules, fmt.Errorf("failed to run go %+v: %w", strings.Join(goGetArgs, " "), err)
} }
a.log("go output: %s", string(goOutput)) a.log("go output: %s", string(goOutput))
successUpgradeModules = append(successUpgradeModules, module) successUpgradedModules = append(successUpgradedModules, module)
color.PrintAppOK(name, fmt.Sprintf("Upgraded [%s] version [%s] to [%s] success", module.Path, module.Version, module.Update.Version)) color.PrintAppOK(name, fmt.Sprintf("Upgraded [%s] version [%s] to [%s] success", module.Path, module.Version, module.Update.Version))
return successUpgradedModules, nil
} }
func (a *action) runGoMod(c *cli.Context, existVendor bool) error {
// go mod tidy // go mod tidy
goModArgs := []string{"mod", "tidy"} goModArgs := []string{"mod", "tidy"}
goOutput, err = exec.CommandContext(c.Context, "go", goModArgs...).CombinedOutput() goOutput, err := exec.CommandContext(c.Context, "go", goModArgs...).CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goModArgs, " "), err) return fmt.Errorf("failed to run go %+v: %w", strings.Join(goModArgs, " "), err)
} }
a.log("go output: %s", string(goOutput)) a.log("go output: %s", string(goOutput))
// If exist git, auto commit if existVendor {
// go mod vendor
goModArgs = []string{"mod", "vendor"}
goOutput, err = exec.CommandContext(c.Context, "go", goModArgs...).CombinedOutput()
if err != nil {
return fmt.Errorf("failed to run go %+v: %w", strings.Join(goModArgs, " "), err)
}
a.log("go output: %s", string(goOutput))
}
return nil
}
func (a *action) runGitCommit(c *cli.Context, successUpgradedModules []Module, existVendor bool) error {
if a.flags.dryRun {
return nil
}
// If not exist git, stop
if _, err := os.Stat(gitDirectory); err != nil { if _, err := os.Stat(gitDirectory); err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return nil return nil
@ -167,20 +241,29 @@ func (a *action) Run(c *cli.Context) error {
return fmt.Errorf("failed to stat %s: %w", gitDirectory, err) return fmt.Errorf("failed to stat %s: %w", gitDirectory, err)
} }
if a.flags.dryRun { // If there is no upgrade module, stop
if len(successUpgradedModules) == 0 {
return nil return nil
} }
if len(successUpgradeModules) == 0 { // git add
return nil gitAddArgs := []string{"add", goModFile, goSumFile}
if existVendor {
gitAddArgs = append(gitAddArgs, vendorDirectory)
} }
gitOutput, err := exec.CommandContext(c.Context, "git", gitAddArgs...).CombinedOutput()
if err != nil {
return fmt.Errorf("failed to run git %+v: %w", strings.Join(gitAddArgs, " "), err)
}
a.log("git output: %s", string(gitOutput))
// git commit
gitCommitMessage := "build: upgrade modules\n" gitCommitMessage := "build: upgrade modules\n"
for _, module := range successUpgradeModules { for _, module := range successUpgradedModules {
gitCommitMessage += fmt.Sprintf("\n%s: %s -> %s", module.Path, module.Version, module.Update.Version) gitCommitMessage += fmt.Sprintf("\n%s: %s -> %s", module.Path, module.Version, module.Update.Version)
} }
gitCommitArgs := []string{"commit", "-m", `"` + gitCommitMessage + `"`} gitCommitArgs := []string{"commit", "-m", `"` + gitCommitMessage + `"`}
gitOutput, err := exec.CommandContext(c.Context, "git", gitCommitArgs...).CombinedOutput() gitOutput, err = exec.CommandContext(c.Context, "git", gitCommitArgs...).CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("failed to run git %+v: %w", strings.Join(gitCommitArgs, " "), err) return fmt.Errorf("failed to run git %+v: %w", strings.Join(gitCommitArgs, " "), err)
} }

View File

@ -21,8 +21,6 @@ const (
usageFlagVerbose = "show what is going on" usageFlagVerbose = "show what is going on"
usageDepsFile = "show what deps need to upgrade" usageDepsFile = "show what deps need to upgrade"
usageDryRun = "demo what would be done" usageDryRun = "demo what would be done"
defaultDepsFile = ".deps"
) )
var aliasFlagVerbose = []string{"v"} var aliasFlagVerbose = []string{"v"}
@ -50,7 +48,7 @@ func NewApp() *App {
&cli.StringFlag{ &cli.StringFlag{
Name: flagDepsFile, Name: flagDepsFile,
Usage: usageDepsFile, Usage: usageDepsFile,
Value: defaultDepsFile, Required: true,
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: flagDryRun, Name: flagDryRun,