diff --git a/providers-sdk/v1/util/version/version.go b/providers-sdk/v1/util/version/version.go index 738a8f8916..5297c2f34e 100644 --- a/providers-sdk/v1/util/version/version.go +++ b/providers-sdk/v1/util/version/version.go @@ -7,10 +7,12 @@ import ( "path/filepath" "regexp" "strings" + "time" mastermind "github.com/Masterminds/semver" tea "github.com/charmbracelet/bubbletea" "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -77,6 +79,10 @@ type providerConf struct { name string } +func (p providerConf) commitTitle() string { + return p.name + "-" + p.version +} + func getConfig(providerPath string) (*providerConf, error) { var conf providerConf @@ -111,47 +117,71 @@ func updateVersion(providerPath string) { return } - out, err := tryUpdate(providerPath, conf) + didUpdate, err := tryUpdate(providerPath, conf) if err != nil { log.Fatal().Err(err).Str("path", providerPath).Msg("failed to process version") } - if out == "" { + if !didUpdate { log.Info().Msg("nothing to do, bye") return } - - if err = os.WriteFile(conf.path, []byte(out), 0o644); err != nil { - log.Fatal().Err(err).Str("path", conf.path).Msg("failed to write file") - } - log.Info().Str("path", conf.path).Msg("updated config") - - commitTitle := conf.name + "-" + conf.version - log.Info().Msg("git add " + conf.path + " && git commit -m \"" + commitTitle + "\"") } -func tryUpdate(repoPath string, conf *providerConf) (string, error) { - commitTitle := conf.name + "-" + conf.version - changes := countChangesSince(commitTitle, repoPath, conf.path) +func tryUpdate(repoPath string, conf *providerConf) (bool, error) { + branchName := "version/" + conf.commitTitle() + changes := countChangesSince(conf.commitTitle(), repoPath, conf.path) logChanges(changes, conf) if changes == 0 { - return "", nil + return false, nil + } + + version, err := bumpVersion(conf.version) + if err != nil || version == "" { + return false, err + } + + res := reVersion.ReplaceAllStringFunc(conf.content, func(v string) string { + return "Version: \"" + version + "\"" + }) + + log.Info().Str("provider", conf.name).Str("version", version).Str("previous", conf.version).Msg("set new version") + conf.version = version + + if err = os.WriteFile(conf.path, []byte(res), 0o644); err != nil { + log.Fatal().Err(err).Str("path", conf.path).Msg("failed to write file") } + log.Info().Str("path", conf.path).Msg("updated config") - v, err := mastermind.NewVersion(conf.version) + if doCommit { + if err = commitChanges(branchName, conf); err != nil { + log.Error().Err(err).Msg("failed to commit changes") + } + } else { + log.Info().Msg("git add " + conf.path + " && git commit -m \"" + conf.commitTitle() + "\"") + } + + return true, nil +} + +func bumpVersion(version string) (string, error) { + v, err := mastermind.NewVersion(version) if err != nil { - return "", errors.New("version '" + conf.version + "' is not a semver") + return "", errors.New("version '" + version + "' is not a semver") } patch := v.IncPatch() minor := v.IncMinor() - major := v.IncMajor() + // TODO: check if the major version of the repo has changed and bump it + + if bumpPatchVersion { + return (&patch).String(), nil + } versions := []string{ - v.String(), + v.String() + " - no change, keep developing", (&patch).String(), (&minor).String(), - (&major).String(), } selection := -1 @@ -167,20 +197,60 @@ func tryUpdate(repoPath string, conf *providerConf) (string, error) { return "", nil } - version := versions[selection] - res := reVersion.ReplaceAllStringFunc(conf.content, func(v string) string { - return "Version: \"" + version + "\"" + return versions[selection], nil +} + +func commitChanges(branchName string, conf *providerConf) error { + repo, err := git.PlainOpen(".") + if err != nil { + return errors.New("failed to open git: " + err.Error()) + } + + headRef, err := repo.Head() + if err != nil { + return errors.New("failed to get git head: " + err.Error()) + } + + worktree, err := repo.Worktree() + if err != nil { + return errors.New("failed to get git tree: " + err.Error()) + } + + ref := plumbing.NewHashReference(plumbing.NewBranchReferenceName(branchName), headRef.Hash()) + err = repo.Storer.SetReference(ref) + if err != nil { + return err + } + + _, err = worktree.Add(conf.path) + if err != nil { + return errors.New("failed to git add: " + err.Error()) + } + + commit, err := worktree.Commit(conf.commitTitle(), &git.CommitOptions{ + Author: &object.Signature{ + Name: "Mondoo", + Email: "hello@mondoo.com", + When: time.Now(), + }, }) + if err != nil { + return errors.New("failed to commit: " + err.Error()) + } - conf.version = version - log.Info().Str("provider", conf.name).Str("version", version).Str("previous", v.String()).Msg("set new version") - return res, nil + _, err = repo.CommitObject(commit) + if err != nil { + return errors.New("commit is not in repo: " + err.Error()) + } + + log.Info().Msg("comitted changes for " + conf.name + " " + conf.version) + return nil } func countChangesSince(commitTitle string, repoPath string, confPath string) int { repo, err := git.PlainOpen(".") if err != nil { - log.Fatal().Err(err).Msg("failed to determine path of provider") + log.Fatal().Err(err).Msg("failed to open git repo") } iter, err := repo.Log(&git.LogOptions{ PathFilter: func(p string) bool { @@ -220,10 +290,16 @@ func countChangesSince(commitTitle string, repoPath string, confPath string) int return count } -var fastMode bool +var ( + fastMode bool + doCommit bool + bumpPatchVersion bool +) func init() { rootCmd.PersistentFlags().BoolVar(&fastMode, "fast", false, "perform fast checking of git repo (not counting changes)") + rootCmd.PersistentFlags().BoolVar(&doCommit, "commit", false, "commit the change to git if there is a version bump") + rootCmd.PersistentFlags().BoolVar(&bumpPatchVersion, "bump-path", false, "automatically bump the patch version") rootCmd.AddCommand(updateCmd, checkCmd) }