From a3b6940d0b0afde004eeb6e2bb44b75b9b2322e1 Mon Sep 17 00:00:00 2001 From: Tom Chauveau Date: Fri, 29 Oct 2021 17:18:45 +0200 Subject: [PATCH 1/6] Improve version checking to also check universe In the future, universe will not be embedded anymore in dagger, instead, it will be remotely vendor from `dagger/universe` repository. To make sure that users always use the latest universe version, the version checking now also verify that universe is not outdated. If universe needs an update, a message is printed to standard output. Signed-off-by: Tom Chauveau --- cmd/dagger/cmd/root.go | 3 +- cmd/dagger/cmd/version.go | 164 +++++++++++++++++++++++++++++++++----- 2 files changed, 148 insertions(+), 19 deletions(-) diff --git a/cmd/dagger/cmd/root.go b/cmd/dagger/cmd/root.go index 1a01a811..c129e579 100644 --- a/cmd/dagger/cmd/root.go +++ b/cmd/dagger/cmd/root.go @@ -48,7 +48,8 @@ func init() { } } rootCmd.PersistentPostRun = func(*cobra.Command, []string) { - warnVersion() + warnDaggerVersion() + warnUniverseVersion() } rootCmd.AddCommand( diff --git a/cmd/dagger/cmd/version.go b/cmd/dagger/cmd/version.go index 7979e252..14cda040 100644 --- a/cmd/dagger/cmd/version.go +++ b/cmd/dagger/cmd/version.go @@ -1,12 +1,14 @@ package cmd import ( + "encoding/json" "fmt" "io/ioutil" "net/http" "os" "path" "runtime" + "sort" "strings" "time" @@ -14,22 +16,25 @@ import ( "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" + "go.dagger.io/dagger/mod" "go.dagger.io/dagger/version" "golang.org/x/term" ) const ( - versionFile = "~/.config/dagger/version-check" - versionURL = "https://releases.dagger.io/dagger/latest_version" + versionFile = "~/.config/dagger/version-check" + versionURL = "https://releases.dagger.io/dagger/latest_version" + universeTagsURL = "https://api.github.com/repos/dagger/universe/tags" ) var ( - versionMessage = "" + daggerVersionMessage = "" + universeVersionMessage = "" ) var versionCmd = &cobra.Command{ Use: "version", - Short: "Print dagger version", + Short: "Print dagger and universe version", // Disable version hook here to avoid double version check PersistentPreRun: func(*cobra.Command, []string) {}, PersistentPostRun: func(*cobra.Command, []string) {}, @@ -41,6 +46,9 @@ var versionCmd = &cobra.Command{ runtime.GOOS, runtime.GOARCH, ) + // TODO Display universe version + // How can I retrieve it if it's not vendor ? + if check := viper.GetBool("check"); check { versionFilePath, err := homedir.Expand(versionFile) if err != nil { @@ -49,15 +57,18 @@ var versionCmd = &cobra.Command{ _ = os.Remove(versionFilePath) checkVersion() - if !warnVersion() { + if !warnDaggerVersion() { fmt.Println("dagger is up to date.") } + if !warnUniverseVersion() { + fmt.Println("universe is up to date.") + } } }, } func init() { - versionCmd.Flags().Bool("check", false, "check if dagger is up to date") + versionCmd.Flags().Bool("check", false, "check if dagger and universe are up to date") if err := viper.BindPFlags(versionCmd.Flags()); err != nil { panic(err) @@ -87,7 +98,7 @@ func isCheckOutdated(path string) bool { return !time.Now().Before(nextCheck) } -func getLatestVersion(currentVersion *goVersion.Version) (*goVersion.Version, error) { +func getDaggerLatestVersion(currentVersion *goVersion.Version) (*goVersion.Version, error) { req, err := http.NewRequest("GET", versionURL, nil) if err != nil { return nil, err @@ -112,15 +123,113 @@ func getLatestVersion(currentVersion *goVersion.Version) (*goVersion.Version, er return goVersion.NewVersion(latestVersion) } -// Compare the binary version with the latest version online -// Return the latest version if current is outdated -func isVersionLatest() (string, error) { +// Compare dagger version with the latest release online +// Return the latest dagger version if current is outdated +func isDaggerVersionLatest() (string, error) { currentVersion, err := goVersion.NewVersion(version.Version) if err != nil { return "", err } - latestVersion, err := getLatestVersion(currentVersion) + latestVersion, err := getDaggerLatestVersion(currentVersion) + if err != nil { + return "", err + } + + if currentVersion.LessThan(latestVersion) { + return latestVersion.String(), nil + } + return "", nil +} + +// Call https://api.github.com/repos/dagger/universe/tags +func listUniverseTags() ([]string, error) { + req, err := http.NewRequest("GET", universeTagsURL, nil) + if err != nil { + return nil, err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var tagsDTO []struct { + Name string `json:"name"` + } + + err = json.Unmarshal(data, &tagsDTO) + if err != nil { + return nil, err + } + + // Reduce DTO to simple string array + tags := []string{} + for _, tag := range tagsDTO { + tags = append(tags, tag.Name) + } + + return tags, nil +} + +func getUniverseLatestVersion() (*goVersion.Version, error) { + tags, err := listUniverseTags() + if err != nil { + return nil, err + } + + // Get latest available version + constraint, err := goVersion.NewConstraint(mod.UniverseVersionConstraint) + if err != nil { + return nil, err + } + + // Retrieve the latest supported universe version + var versions []*goVersion.Version + for _, tag := range tags { + if !strings.HasPrefix(tag, "v") { + continue + } + + v, err := goVersion.NewVersion(tag) + if err != nil { + continue + } + + if constraint.Check(v) { + versions = append(versions, v) + } + } + + if len(versions) == 0 { + return nil, fmt.Errorf("universe repository has no version matching the required version") + } + + sort.Sort(sort.Reverse(goVersion.Collection(versions))) + return versions[0], nil +} + +func getUniverseCurrentVersion() (*goVersion.Version, error) { + // TODO Should be replaced with the current universe version + // How I can fetch it + return goVersion.NewVersion("0.1.0") +} + +// Compare the universe version with the latest version online +// Return the latest universe version if the current is outdated +func isUniverseVersionLatest() (string, error) { + currentVersion, err := getUniverseCurrentVersion() + if err != nil { + return "", err + } + + latestVersion, err := getUniverseLatestVersion() if err != nil { return "", err } @@ -154,14 +263,24 @@ func checkVersion() { return } - // Check timestamp - latestVersion, err := isVersionLatest() + // Check version + universeLatestVersion, err := isUniverseVersionLatest() if err != nil { return } - if latestVersion != "" { - versionMessage = fmt.Sprintf("\nA new version is available (%s), please go to https://github.com/dagger/dagger/doc/install.md for instructions.", latestVersion) + if universeLatestVersion != "" { + universeVersionMessage = fmt.Sprintf("A new version of universe is available (%s), please run 'dagger mod get github.com/dagger/universe/stdlib'", universeLatestVersion) + } + + // Check timestamp + daggerLatestVersion, err := isDaggerVersionLatest() + if err != nil { + return + } + + if daggerLatestVersion != "" { + daggerVersionMessage = fmt.Sprintf("\nA new version of dagger is available (%s), please go to https://github.com/dagger/dagger/doc/install.md for instructions.", daggerLatestVersion) } // Update check timestamps file @@ -169,8 +288,8 @@ func checkVersion() { ioutil.WriteFile(path.Join(versionFilePath), []byte(now), 0600) } -func warnVersion() bool { - if versionMessage == "" { +func warnDaggerVersion() bool { + if daggerVersionMessage == "" { return false } @@ -185,6 +304,15 @@ func warnVersion() bool { } // Print default message - fmt.Println(versionMessage) + fmt.Println(daggerVersionMessage) + return true +} + +func warnUniverseVersion() bool { + if universeVersionMessage == "" { + return false + } + + fmt.Println(universeVersionMessage) return true } From 927762481a37de596cb8f73c4b0c7b462d4620d3 Mon Sep 17 00:00:00 2001 From: Tom Chauveau Date: Fri, 29 Oct 2021 18:52:32 +0200 Subject: [PATCH 2/6] Fix `dagger mod get` to stop requiring environment Signed-off-by: Tom Chauveau --- cmd/dagger/cmd/mod/get.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/dagger/cmd/mod/get.go b/cmd/dagger/cmd/mod/get.go index 20df6180..bcc48d15 100644 --- a/cmd/dagger/cmd/mod/get.go +++ b/cmd/dagger/cmd/mod/get.go @@ -26,8 +26,7 @@ var getCmd = &cobra.Command{ ctx := lg.WithContext(cmd.Context()) project := common.CurrentProject(ctx) - st := common.CurrentEnvironmentState(ctx, project) - doneCh := common.TrackProjectCommand(ctx, cmd, project, st, &telemetry.Property{ + doneCh := common.TrackProjectCommand(ctx, cmd, project, nil, &telemetry.Property{ Name: "packages", Value: args, }) From 5f0a4202c91578c2af33182f10448034783e7035 Mon Sep 17 00:00:00 2001 From: Tom Chauveau Date: Fri, 29 Oct 2021 19:31:59 +0200 Subject: [PATCH 3/6] Complete version checking with `getUniverseCurrentVersion` Dagger now compare the remote universe version with the one written in dagger.mod. I've also added logs to easily debug code Signed-off-by: Tom Chauveau --- cmd/dagger/cmd/version.go | 45 ++++++++++++++++++++++++++++++++++----- mod/file.go | 6 +++--- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/cmd/dagger/cmd/version.go b/cmd/dagger/cmd/version.go index 14cda040..1b0076a3 100644 --- a/cmd/dagger/cmd/version.go +++ b/cmd/dagger/cmd/version.go @@ -1,6 +1,7 @@ package cmd import ( + "context" "encoding/json" "fmt" "io/ioutil" @@ -16,6 +17,8 @@ import ( "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" + "go.dagger.io/dagger/cmd/dagger/cmd/common" + "go.dagger.io/dagger/cmd/dagger/logger" "go.dagger.io/dagger/mod" "go.dagger.io/dagger/version" "golang.org/x/term" @@ -46,8 +49,10 @@ var versionCmd = &cobra.Command{ runtime.GOOS, runtime.GOARCH, ) - // TODO Display universe version - // How can I retrieve it if it's not vendor ? + universeVersion, err := getUniverseCurrentVersion() + if err == nil { + fmt.Printf("universe %s\n", universeVersion.Original()) + } if check := viper.GetBool("check"); check { versionFilePath, err := homedir.Expand(versionFile) @@ -215,10 +220,33 @@ func getUniverseLatestVersion() (*goVersion.Version, error) { return versions[0], nil } +// Retrieve the current universe version from `cue.mod/dagger.mod` func getUniverseCurrentVersion() (*goVersion.Version, error) { - // TODO Should be replaced with the current universe version - // How I can fetch it - return goVersion.NewVersion("0.1.0") + project := common.CurrentProject(context.Background()) + pathMod := path.Join(project.Path, mod.ModFilePath) + fileMod, err := os.Open(pathMod) + if err != nil { + return nil, err + } + + defer fileMod.Close() + data, err := ioutil.ReadAll(fileMod) + if err != nil { + return nil, err + } + + currentVersion := "" + modules := strings.Split(string(data), "\n") + for _, module := range modules { + if !strings.HasPrefix(module, "alpha.dagger.io") { + continue + } + + // Retrieve tag + tag := strings.Split(module, " ") + currentVersion = tag[1] + } + return goVersion.NewVersion(currentVersion) } // Compare the universe version with the latest version online @@ -241,8 +269,11 @@ func isUniverseVersionLatest() (string, error) { } func checkVersion() { + lg := logger.New() + if version.Version == version.DevelopmentVersion { // running devel version + lg.Debug().Msg("ignore check version on devel version") return } @@ -264,8 +295,10 @@ func checkVersion() { } // Check version + lg.Debug().Msg("check for universe latest version...") universeLatestVersion, err := isUniverseVersionLatest() if err != nil { + lg.Debug().Msg(err.Error()) return } @@ -274,8 +307,10 @@ func checkVersion() { } // Check timestamp + lg.Debug().Msg("check for dagger latest version...") daggerLatestVersion, err := isDaggerVersionLatest() if err != nil { + lg.Debug().Msg(err.Error()) return } diff --git a/mod/file.go b/mod/file.go index 1cd4d89b..67a4f9ed 100644 --- a/mod/file.go +++ b/mod/file.go @@ -17,7 +17,7 @@ import ( ) const ( - modFilePath = "./cue.mod/dagger.mod" + ModFilePath = "./cue.mod/dagger.mod" sumFilePath = "./cue.mod/dagger.sum" lockFilePath = "./cue.mod/dagger.lock" destBasePath = "./cue.mod/pkg" @@ -31,7 +31,7 @@ type file struct { } func readPath(workspacePath string) (*file, error) { - pMod := path.Join(workspacePath, modFilePath) + pMod := path.Join(workspacePath, ModFilePath) fMod, err := os.Open(pMod) if err != nil { if !errors.Is(err, fs.ErrNotExist) { @@ -276,7 +276,7 @@ func (f *file) write() error { bMod.WriteString(fmt.Sprintf("%s %s\n", r.fullPath(), r.version)) } - err := ioutil.WriteFile(path.Join(f.workspacePath, modFilePath), bMod.Bytes(), 0600) + err := ioutil.WriteFile(path.Join(f.workspacePath, ModFilePath), bMod.Bytes(), 0600) if err != nil { return err } From c808f4e828ce2ecade6cb4cc29dcfc4005faa1ac Mon Sep 17 00:00:00 2001 From: Tom Chauveau Date: Fri, 29 Oct 2021 19:34:37 +0200 Subject: [PATCH 4/6] Add tracking on `dagger version` Signed-off-by: Tom Chauveau --- cmd/dagger/cmd/version.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/cmd/dagger/cmd/version.go b/cmd/dagger/cmd/version.go index 1b0076a3..49565b26 100644 --- a/cmd/dagger/cmd/version.go +++ b/cmd/dagger/cmd/version.go @@ -20,6 +20,7 @@ import ( "go.dagger.io/dagger/cmd/dagger/cmd/common" "go.dagger.io/dagger/cmd/dagger/logger" "go.dagger.io/dagger/mod" + "go.dagger.io/dagger/telemetry" "go.dagger.io/dagger/version" "golang.org/x/term" ) @@ -43,6 +44,14 @@ var versionCmd = &cobra.Command{ PersistentPostRun: func(*cobra.Command, []string) {}, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { + ctx := cmd.Context() + + project := common.CurrentProject(ctx) + doneCh := common.TrackProjectCommand(ctx, cmd, project, nil, &telemetry.Property{ + Name: "version", + Value: args, + }) + fmt.Printf("dagger %s (%s) %s/%s\n", version.Version, version.Revision, @@ -69,6 +78,8 @@ var versionCmd = &cobra.Command{ fmt.Println("universe is up to date.") } } + + <-doneCh }, } From 8eb01d850b7b26512cca5135058d02c4870c3abc Mon Sep 17 00:00:00 2001 From: Tom Chauveau Date: Fri, 29 Oct 2021 19:47:20 +0200 Subject: [PATCH 5/6] Fix context issue on dagger version Signed-off-by: Tom Chauveau --- cmd/dagger/cmd/version.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/dagger/cmd/version.go b/cmd/dagger/cmd/version.go index 49565b26..3d62b841 100644 --- a/cmd/dagger/cmd/version.go +++ b/cmd/dagger/cmd/version.go @@ -15,10 +15,10 @@ import ( goVersion "github.com/hashicorp/go-version" "github.com/mitchellh/go-homedir" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/viper" "go.dagger.io/dagger/cmd/dagger/cmd/common" - "go.dagger.io/dagger/cmd/dagger/logger" "go.dagger.io/dagger/mod" "go.dagger.io/dagger/telemetry" "go.dagger.io/dagger/version" @@ -280,11 +280,11 @@ func isUniverseVersionLatest() (string, error) { } func checkVersion() { - lg := logger.New() + lg := log.Ctx(context.Background()).With().Logger() if version.Version == version.DevelopmentVersion { // running devel version - lg.Debug().Msg("ignore check version on devel version") + lg.Debug().Msg("version checking ignored on development version") return } From 3ebd076c5d92317829377900f130f294c5200219 Mon Sep 17 00:00:00 2001 From: Tom Chauveau Date: Fri, 29 Oct 2021 22:15:58 +0200 Subject: [PATCH 6/6] Fix argoCD timeout Signed-off-by: Tom Chauveau --- stdlib/universe.bats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/universe.bats b/stdlib/universe.bats index 4a42172b..9a3198d0 100644 --- a/stdlib/universe.bats +++ b/stdlib/universe.bats @@ -248,7 +248,7 @@ setup() { dagger -e argocd-infra up # Wait for infra to be ready - kubectl -n argocd wait --for=condition=available deployment -l "app.kubernetes.io/part-of=argocd" --timeout=45s + kubectl -n argocd wait --for=condition=available deployment -l "app.kubernetes.io/part-of=argocd" --timeout=100s # Forward port # We need to kill subprocess to avoid infinity loop