Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Atmos Version Check Configuration #844

Merged
merged 19 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions atmos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,9 @@ settings:
# If the source and destination lists have the same length, all items in the destination lists are
# deep-merged with all items in the source list.
list_merge_strategy: replace

version:
check:
enabled: true
timeout: 1000 # ms
frequency: 3m
aknysh marked this conversation as resolved.
Show resolved Hide resolved
63 changes: 53 additions & 10 deletions cmd/cmd_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path"
"strings"
"time"

"github.com/fatih/color"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -428,18 +429,60 @@ func printMessageForMissingAtmosConfig(cliConfig schema.CliConfiguration) {
u.PrintMessage("https://atmos.tools/quick-start\n")
}

// customHelpMessageToUpgradeToAtmosLatestRelease adds Atmos version info at the end of each help commnad
func customHelpMessageToUpgradeToAtmosLatestRelease(cmd *cobra.Command, args []string) {
originalHelpFunc(cmd, args)
// Check for the latest Atmos release on GitHub
// CheckForAtmosUpdateAndPrintMessage checks if a version update is needed and prints a message if a newer version is found.
// It loads the cache, decides if it's time to check for updates, compares the current version to the latest available release,
// and if newer, prints the update message. It also updates the cache's timestamp after printing.
func CheckForAtmosUpdateAndPrintMessage(cliConfig schema.CliConfiguration) {
// If version checking is disabled in the configuration, do nothing
if !cliConfig.Version.Check.Enabled {
return
}

// Load the cache
cacheCfg, err := cfg.LoadCache()
if err != nil {
u.LogWarning(cliConfig, fmt.Sprintf("Could not load cache: %s", err))
return
}

// Determine if it's time to check for updates based on frequency and last_checked
if !cfg.ShouldCheckForUpdates(cacheCfg.LastChecked, cliConfig.Version.Check.Frequency) {
// Not due for another check yet, so return without printing anything
return
}

// Get the latest Atmos release from GitHub
latestReleaseTag, err := u.GetLatestGitHubRepoRelease("cloudposse", "atmos")
if err == nil && latestReleaseTag != "" {
latestRelease := strings.TrimPrefix(latestReleaseTag, "v")
currentRelease := strings.TrimPrefix(version.Version, "v")
if latestRelease != currentRelease {
u.PrintMessageToUpgradeToAtmosLatestRelease(latestRelease)
}
if err != nil {
u.LogWarning(cliConfig, fmt.Sprintf("Failed to retrieve latest Atmos release info: %s", err))
return
}

if latestReleaseTag == "" {
u.LogWarning(cliConfig, "No release information available")
return
}
Listener430 marked this conversation as resolved.
Show resolved Hide resolved

// Trim "v" prefix to compare versions
latestVersion := strings.TrimPrefix(latestReleaseTag, "v")
currentVersion := strings.TrimPrefix(version.Version, "v")

// If the versions differ, print the update message
if latestVersion != currentVersion {
Listener430 marked this conversation as resolved.
Show resolved Hide resolved
u.PrintMessageToUpgradeToAtmosLatestRelease(latestVersion)
}

// Update the cache to mark the current timestamp
cacheCfg.LastChecked = time.Now().Unix()
if saveErr := cfg.SaveCache(cacheCfg); saveErr != nil {
u.LogWarning(cliConfig, fmt.Sprintf("Unable to save cache: %s", saveErr))

}
}

func customHelpMessageToUpgradeToAtmosLatestRelease(cmd *cobra.Command, args []string) {
originalHelpFunc(cmd, args)
CheckForAtmosUpdateAndPrintMessage(cliConfig)
}

// Check Atmos is version command
Expand Down
15 changes: 2 additions & 13 deletions cmd/helmfile.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package cmd

import (
"strings"

"github.com/samber/lo"
"github.com/spf13/cobra"

e "github.com/cloudposse/atmos/internal/exec"
"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
"github.com/cloudposse/atmos/pkg/version"
)

// helmfileCmd represents the base command for all helmfile sub-commands
Expand All @@ -34,18 +31,10 @@ var helmfileCmd = &cobra.Command{
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}

// Check for the latest Atmos release on GitHub and print update message
latestReleaseTag, err := u.GetLatestGitHubRepoRelease("cloudposse", "atmos")
if err == nil && latestReleaseTag != "" {
latestRelease := strings.TrimPrefix(latestReleaseTag, "v")
currentRelease := strings.TrimPrefix(version.Version, "v")
if latestRelease != currentRelease {
u.PrintMessageToUpgradeToAtmosLatestRelease(latestRelease)
}
}
// Exit on help
if info.NeedHelp {
// Check for the latest Atmos release on GitHub and print update message
CheckForAtmosUpdateAndPrintMessage(cliConfig)
Listener430 marked this conversation as resolved.
Show resolved Hide resolved
return
}
// Check Atmos configuration
Expand Down
30 changes: 16 additions & 14 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
u "github.com/cloudposse/atmos/pkg/utils"
)

var cliConfig schema.CliConfiguration

// originalHelpFunc holds Cobra's original help function to avoid recursion.
var originalHelpFunc func(*cobra.Command, []string)

Expand Down Expand Up @@ -72,14 +74,6 @@ func Execute() error {
Flags: cc.Bold,
})

// Save the original help function to prevent infinite recursion when overriding it.
// This allows us to call the original help functionality within our custom help function.
originalHelpFunc = RootCmd.HelpFunc()

// Override the help function with a custom one that adds an upgrade message after displaying help.
// This custom help function will call the original help function and then display the bordered message.
RootCmd.SetHelpFunc(customHelpMessageToUpgradeToAtmosLatestRelease)

// Check if the `help` flag is passed and print a styled Atmos logo to the terminal before printing the help
err := RootCmd.ParseFlags(os.Args)
if err != nil && errors.Is(err, pflag.ErrHelp) {
Expand All @@ -89,21 +83,29 @@ func Execute() error {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
}

// InitCliConfig finds and merges CLI configurations in the following order:
// system dir, home dir, current dir, ENV vars, command-line arguments
// Here we need the custom commands from the config
cliConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, false)
if err != nil && !errors.Is(err, cfg.NotFound) {
var initErr error
cliConfig, initErr = cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, false)
if initErr != nil && !errors.Is(initErr, cfg.NotFound) {
if isVersionCommand() {
u.LogTrace(schema.CliConfiguration{}, fmt.Sprintf("warning: CLI configuration 'atmos.yaml' file not found. Error: %s", err))
u.LogTrace(schema.CliConfiguration{}, fmt.Sprintf("warning: CLI configuration 'atmos.yaml' file not found. Error: %s", initErr))
} else {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
u.LogErrorAndExit(schema.CliConfiguration{}, initErr)
}
}

// Save the original help function to prevent infinite recursion when overriding it.
// This allows us to call the original help functionality within our custom help function.
originalHelpFunc = RootCmd.HelpFunc()

// Override the help function with a custom one that adds an upgrade message after displaying help.
// This custom help function will call the original help function and then display the bordered message.
RootCmd.SetHelpFunc(customHelpMessageToUpgradeToAtmosLatestRelease)

// If CLI configuration was found, process its custom commands and command aliases
if err == nil {
if initErr == nil {
err = processCustomCommands(cliConfig, cliConfig.Commands, RootCmd, true)
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
Expand Down
15 changes: 3 additions & 12 deletions cmd/terraform.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package cmd

import (
"strings"

"github.com/samber/lo"
"github.com/spf13/cobra"

e "github.com/cloudposse/atmos/internal/exec"
"github.com/cloudposse/atmos/pkg/schema"
u "github.com/cloudposse/atmos/pkg/utils"
"github.com/cloudposse/atmos/pkg/version"
)

// terraformCmd represents the base command for all terraform sub-commands
Expand All @@ -35,17 +32,11 @@ var terraformCmd = &cobra.Command{
if err != nil {
u.LogErrorAndExit(schema.CliConfiguration{}, err)
}
// Check for the latest Atmos release on GitHub and print update message
latestReleaseTag, err := u.GetLatestGitHubRepoRelease("cloudposse", "atmos")
if err == nil && latestReleaseTag != "" {
latestRelease := strings.TrimPrefix(latestReleaseTag, "v")
currentRelease := strings.TrimPrefix(version.Version, "v")
if latestRelease != currentRelease {
u.PrintMessageToUpgradeToAtmosLatestRelease(latestRelease)
}
}

// Exit on help
if info.NeedHelp {
// Check for the latest Atmos release on GitHub and print update message
CheckForAtmosUpdateAndPrintMessage(cliConfig)
Listener430 marked this conversation as resolved.
Show resolved Hide resolved
return
}
// Check Atmos configuration
Expand Down
31 changes: 24 additions & 7 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/cloudposse/atmos/pkg/version"
)

var checkFlag bool

var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the CLI version",
Expand All @@ -29,18 +31,33 @@ var versionCmd = &cobra.Command{
u.PrintMessage(fmt.Sprintf("\U0001F47D Atmos %s on %s/%s", version.Version, runtime.GOOS, runtime.GOARCH))
fmt.Println()

// Check for the latest Atmos release on GitHub
latestReleaseTag, err := u.GetLatestGitHubRepoRelease("cloudposse", "atmos")
if err == nil && latestReleaseTag != "" {
latestRelease := strings.TrimPrefix(latestReleaseTag, "v")
currentRelease := strings.TrimPrefix(version.Version, "v")
if latestRelease != currentRelease {
u.PrintMessageToUpgradeToAtmosLatestRelease(latestRelease)
if checkFlag {
// Check for the latest Atmos release on GitHub
latestReleaseTag, err := u.GetLatestGitHubRepoRelease("cloudposse", "atmos")
if err == nil && latestReleaseTag != "" {
if err != nil {
u.LogWarning(schema.CliConfiguration{}, fmt.Sprintf("Failed to check for updates: %v", err))
return
}
if latestReleaseTag == "" {
u.LogWarning(schema.CliConfiguration{}, "No release information available")
return
}
latestRelease := strings.TrimPrefix(latestReleaseTag, "v")
currentRelease := strings.TrimPrefix(version.Version, "v")
if latestRelease != currentRelease {
u.PrintMessageToUpgradeToAtmosLatestRelease(latestRelease)
}
}
return
Listener430 marked this conversation as resolved.
Show resolved Hide resolved
}

// Check for the cache and print update message
CheckForAtmosUpdateAndPrintMessage(cliConfig)
},
}

func init() {
versionCmd.Flags().BoolVarP(&checkFlag, "check", "c", false, "Run additional checks after displaying version info")
RootCmd.AddCommand(versionCmd)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/elewis787/boa v0.1.2
github.com/fatih/color v1.18.0
github.com/go-git/go-git/v5 v5.12.0
github.com/gofrs/flock v0.12.1
github.com/google/go-containerregistry v0.20.2
github.com/google/go-github/v59 v59.0.0
github.com/google/uuid v1.6.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,8 @@ github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
Expand Down
Loading
Loading