Merge pull request #1085 from TomChv/feat/check-universe-version

Improve version checking to also check universe
This commit is contained in:
Sam Alba 2021-11-08 15:23:59 -08:00 committed by GitHub
commit 6acc7e2c4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 198 additions and 24 deletions

View File

@ -26,8 +26,7 @@ var getCmd = &cobra.Command{
ctx := lg.WithContext(cmd.Context()) ctx := lg.WithContext(cmd.Context())
project := common.CurrentProject(ctx) project := common.CurrentProject(ctx)
st := common.CurrentEnvironmentState(ctx, project) doneCh := common.TrackProjectCommand(ctx, cmd, project, nil, &telemetry.Property{
doneCh := common.TrackProjectCommand(ctx, cmd, project, st, &telemetry.Property{
Name: "packages", Name: "packages",
Value: args, Value: args,
}) })

View File

@ -48,7 +48,8 @@ func init() {
} }
} }
rootCmd.PersistentPostRun = func(*cobra.Command, []string) { rootCmd.PersistentPostRun = func(*cobra.Command, []string) {
warnVersion() warnDaggerVersion()
warnUniverseVersion()
} }
rootCmd.AddCommand( rootCmd.AddCommand(

View File

@ -1,19 +1,26 @@
package cmd package cmd
import ( import (
"context"
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os" "os"
"path" "path"
"runtime" "runtime"
"sort"
"strings" "strings"
"time" "time"
goVersion "github.com/hashicorp/go-version" goVersion "github.com/hashicorp/go-version"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"go.dagger.io/dagger/cmd/dagger/cmd/common"
"go.dagger.io/dagger/mod"
"go.dagger.io/dagger/telemetry"
"go.dagger.io/dagger/version" "go.dagger.io/dagger/version"
"golang.org/x/term" "golang.org/x/term"
) )
@ -21,26 +28,41 @@ import (
const ( const (
versionFile = "~/.config/dagger/version-check" versionFile = "~/.config/dagger/version-check"
versionURL = "https://releases.dagger.io/dagger/latest_version" versionURL = "https://releases.dagger.io/dagger/latest_version"
universeTagsURL = "https://api.github.com/repos/dagger/universe/tags"
) )
var ( var (
versionMessage = "" daggerVersionMessage = ""
universeVersionMessage = ""
) )
var versionCmd = &cobra.Command{ var versionCmd = &cobra.Command{
Use: "version", Use: "version",
Short: "Print dagger version", Short: "Print dagger and universe version",
// Disable version hook here to avoid double version check // Disable version hook here to avoid double version check
PersistentPreRun: func(*cobra.Command, []string) {}, PersistentPreRun: func(*cobra.Command, []string) {},
PersistentPostRun: func(*cobra.Command, []string) {}, PersistentPostRun: func(*cobra.Command, []string) {},
Args: cobra.NoArgs, Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) { 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", fmt.Printf("dagger %s (%s) %s/%s\n",
version.Version, version.Version,
version.Revision, version.Revision,
runtime.GOOS, runtime.GOARCH, runtime.GOOS, runtime.GOARCH,
) )
universeVersion, err := getUniverseCurrentVersion()
if err == nil {
fmt.Printf("universe %s\n", universeVersion.Original())
}
if check := viper.GetBool("check"); check { if check := viper.GetBool("check"); check {
versionFilePath, err := homedir.Expand(versionFile) versionFilePath, err := homedir.Expand(versionFile)
if err != nil { if err != nil {
@ -49,15 +71,20 @@ var versionCmd = &cobra.Command{
_ = os.Remove(versionFilePath) _ = os.Remove(versionFilePath)
checkVersion() checkVersion()
if !warnVersion() { if !warnDaggerVersion() {
fmt.Println("dagger is up to date.") fmt.Println("dagger is up to date.")
} }
if !warnUniverseVersion() {
fmt.Println("universe is up to date.")
} }
}
<-doneCh
}, },
} }
func init() { 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 { if err := viper.BindPFlags(versionCmd.Flags()); err != nil {
panic(err) panic(err)
@ -87,7 +114,7 @@ func isCheckOutdated(path string) bool {
return !time.Now().Before(nextCheck) 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) req, err := http.NewRequest("GET", versionURL, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -112,15 +139,136 @@ func getLatestVersion(currentVersion *goVersion.Version) (*goVersion.Version, er
return goVersion.NewVersion(latestVersion) return goVersion.NewVersion(latestVersion)
} }
// Compare the binary version with the latest version online // Compare dagger version with the latest release online
// Return the latest version if current is outdated // Return the latest dagger version if current is outdated
func isVersionLatest() (string, error) { func isDaggerVersionLatest() (string, error) {
currentVersion, err := goVersion.NewVersion(version.Version) currentVersion, err := goVersion.NewVersion(version.Version)
if err != nil { if err != nil {
return "", err 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
}
// Retrieve the current universe version from `cue.mod/dagger.mod`
func getUniverseCurrentVersion() (*goVersion.Version, error) {
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
// 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 { if err != nil {
return "", err return "", err
} }
@ -132,8 +280,11 @@ func isVersionLatest() (string, error) {
} }
func checkVersion() { func checkVersion() {
lg := log.Ctx(context.Background()).With().Logger()
if version.Version == version.DevelopmentVersion { if version.Version == version.DevelopmentVersion {
// running devel version // running devel version
lg.Debug().Msg("version checking ignored on development version")
return return
} }
@ -154,14 +305,28 @@ func checkVersion() {
return return
} }
// Check timestamp // Check version
latestVersion, err := isVersionLatest() lg.Debug().Msg("check for universe latest version...")
universeLatestVersion, err := isUniverseVersionLatest()
if err != nil { if err != nil {
lg.Debug().Msg(err.Error())
return return
} }
if latestVersion != "" { if universeLatestVersion != "" {
versionMessage = fmt.Sprintf("\nA new version is available (%s), please go to https://github.com/dagger/dagger/doc/install.md for instructions.", latestVersion) universeVersionMessage = fmt.Sprintf("A new version of universe is available (%s), please run 'dagger mod get github.com/dagger/universe/stdlib'", universeLatestVersion)
}
// Check timestamp
lg.Debug().Msg("check for dagger latest version...")
daggerLatestVersion, err := isDaggerVersionLatest()
if err != nil {
lg.Debug().Msg(err.Error())
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 // Update check timestamps file
@ -169,8 +334,8 @@ func checkVersion() {
ioutil.WriteFile(path.Join(versionFilePath), []byte(now), 0600) ioutil.WriteFile(path.Join(versionFilePath), []byte(now), 0600)
} }
func warnVersion() bool { func warnDaggerVersion() bool {
if versionMessage == "" { if daggerVersionMessage == "" {
return false return false
} }
@ -185,6 +350,15 @@ func warnVersion() bool {
} }
// Print default message // Print default message
fmt.Println(versionMessage) fmt.Println(daggerVersionMessage)
return true
}
func warnUniverseVersion() bool {
if universeVersionMessage == "" {
return false
}
fmt.Println(universeVersionMessage)
return true return true
} }

View File

@ -17,7 +17,7 @@ import (
) )
const ( const (
modFilePath = "./cue.mod/dagger.mod" ModFilePath = "./cue.mod/dagger.mod"
sumFilePath = "./cue.mod/dagger.sum" sumFilePath = "./cue.mod/dagger.sum"
lockFilePath = "./cue.mod/dagger.lock" lockFilePath = "./cue.mod/dagger.lock"
destBasePath = "./cue.mod/pkg" destBasePath = "./cue.mod/pkg"
@ -31,7 +31,7 @@ type file struct {
} }
func readPath(workspacePath string) (*file, error) { func readPath(workspacePath string) (*file, error) {
pMod := path.Join(workspacePath, modFilePath) pMod := path.Join(workspacePath, ModFilePath)
fMod, err := os.Open(pMod) fMod, err := os.Open(pMod)
if err != nil { if err != nil {
if !errors.Is(err, fs.ErrNotExist) { 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)) 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 { if err != nil {
return err return err
} }