-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[gitpod-cli] Add auto-updating capabilities (#19056)
* Add version command * Restructure config package * Bring back config get and config set * Support login host without protocol scheme * Add autoupdate functionality * Generate update manifest during build * Better update failure behavior * Add latest to version command * Add version update command * Use cannonical semver form
- Loading branch information
Showing
23 changed files
with
1,070 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) 2023 Gitpod GmbH. All rights reserved. | ||
// Licensed under the GNU Affero General Public License (AGPL). | ||
// See License.AGPL.txt in the project root for license information. | ||
|
||
package cmd | ||
|
||
import ( | ||
"github.com/gitpod-io/local-app/pkg/config" | ||
"github.com/gitpod-io/local-app/pkg/prettyprint" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var configGetCmd = &cobra.Command{ | ||
Use: "get", | ||
Short: "Get an individual config value in the config file", | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
cmd.SilenceUsage = true | ||
|
||
cfg := config.FromContext(cmd.Context()) | ||
|
||
return WriteTabular([]struct { | ||
Telemetry bool `header:"Telemetry"` | ||
Autoupdate bool `header:"Autoupdate"` | ||
}{ | ||
{Telemetry: cfg.Telemetry.Enabled, Autoupdate: cfg.Autoupdate}, | ||
}, configGetOpts.Format, prettyprint.WriterFormatNarrow) | ||
}, | ||
} | ||
|
||
var configGetOpts struct { | ||
Format formatOpts | ||
} | ||
|
||
func init() { | ||
configCmd.AddCommand(configGetCmd) | ||
addFormatFlags(configGetCmd, &configGetOpts.Format) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright (c) 2023 Gitpod GmbH. All rights reserved. | ||
// Licensed under the GNU Affero General Public License (AGPL). | ||
// See License.AGPL.txt in the project root for license information. | ||
|
||
package cmd | ||
|
||
import ( | ||
"log/slog" | ||
|
||
"github.com/gitpod-io/local-app/pkg/config" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var configSetCmd = &cobra.Command{ | ||
Use: "set", | ||
Short: "Set an individual config value in the config file", | ||
Long: `Set an individual config value in the config file. | ||
Example: | ||
# Disable telemetry | ||
local-app config set --telemetry=false | ||
# Disable autoupdate | ||
local-app config set --autoupdate=false | ||
# Enable telemetry and autoupdate | ||
local-app config set --telemetry=true --autoupdate=true | ||
`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
cmd.SilenceUsage = true | ||
|
||
var update bool | ||
cfg := config.FromContext(cmd.Context()) | ||
if cmd.Flags().Changed("autoupdate") { | ||
cfg.Autoupdate = configSetOpts.Autoupdate | ||
update = true | ||
} | ||
if cmd.Flags().Changed("telemetry") { | ||
cfg.Telemetry.Enabled = configSetOpts.Telemetry | ||
update = true | ||
} | ||
if !update { | ||
return cmd.Help() | ||
} | ||
|
||
slog.Debug("updating config") | ||
err := config.SaveConfig(cfg.Filename, cfg) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
}, | ||
} | ||
|
||
var configSetOpts struct { | ||
Autoupdate bool | ||
Telemetry bool | ||
} | ||
|
||
func init() { | ||
configCmd.AddCommand(configSetCmd) | ||
configSetCmd.Flags().BoolVar(&configSetOpts.Autoupdate, "autoupdate", true, "enable/disable autoupdate") | ||
configSetCmd.Flags().BoolVar(&configSetOpts.Telemetry, "telemetry", true, "enable/disable telemetry") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright (c) 2023 Gitpod GmbH. All rights reserved. | ||
// Licensed under the GNU Affero General Public License (AGPL). | ||
// See License.AGPL.txt in the project root for license information. | ||
|
||
package cmd | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/gitpod-io/local-app/pkg/config" | ||
"github.com/gitpod-io/local-app/pkg/constants" | ||
"github.com/gitpod-io/local-app/pkg/selfupdate" | ||
"github.com/sagikazarmark/slog-shim" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var versionUpdateCmd = &cobra.Command{ | ||
Use: "update", | ||
Short: "Updates the CLI to the latest version", | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
cmd.SilenceUsage = true | ||
|
||
dlctx, cancel := context.WithTimeout(cmd.Context(), 30*time.Second) | ||
defer cancel() | ||
|
||
cfg := config.FromContext(cmd.Context()) | ||
gpctx, err := cfg.GetActiveContext() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
mf, err := selfupdate.DownloadManifest(dlctx, gpctx.Host.URL.String()) | ||
if err != nil { | ||
return err | ||
} | ||
if !selfupdate.NeedsUpdate(constants.Version, mf) { | ||
slog.Info("already up to date") | ||
return nil | ||
} | ||
|
||
slog.Info("updating to latest version " + mf.Version.String()) | ||
err = selfupdate.ReplaceSelf(dlctx, mf) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
func init() { | ||
versionCmd.AddCommand(versionUpdateCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright (c) 2023 Gitpod GmbH. All rights reserved. | ||
// Licensed under the GNU Affero General Public License (AGPL). | ||
// See License.AGPL.txt in the project root for license information. | ||
|
||
package cmd | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
"runtime" | ||
"testing" | ||
|
||
"github.com/Masterminds/semver/v3" | ||
"github.com/gitpod-io/local-app/pkg/config" | ||
"github.com/gitpod-io/local-app/pkg/constants" | ||
"github.com/gitpod-io/local-app/pkg/selfupdate" | ||
"github.com/opencontainers/go-digest" | ||
) | ||
|
||
func TestVersionUpdateCmd(t *testing.T) { | ||
RunCommandTests(t, []CommandTest{ | ||
{ | ||
Name: "happy path", | ||
Commandline: []string{"version", "update"}, | ||
PrepServer: func(mux *http.ServeMux) { | ||
newBinary := []byte("#!/bin/bash\necho hello world") | ||
mux.HandleFunc(selfupdate.GitpodCLIBasePath+"/manifest.json", func(w http.ResponseWriter, r *http.Request) { | ||
mf, err := json.Marshal(selfupdate.Manifest{ | ||
Version: semver.MustParse("v9999.0"), | ||
Binaries: []selfupdate.Binary{ | ||
{ | ||
Filename: "gitpod", | ||
OS: runtime.GOOS, | ||
Arch: runtime.GOARCH, | ||
Digest: digest.FromBytes(newBinary), | ||
}, | ||
}, | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
_, _ = w.Write(mf) | ||
}) | ||
mux.HandleFunc(selfupdate.GitpodCLIBasePath+"/gitpod", func(w http.ResponseWriter, r *http.Request) { | ||
_, _ = w.Write(newBinary) | ||
}) | ||
}, | ||
Config: AddActiveTestContext(&config.Config{}), | ||
}, | ||
{ | ||
Name: "no update needed", | ||
Commandline: []string{"version", "update"}, | ||
PrepServer: func(mux *http.ServeMux) { | ||
mux.HandleFunc(selfupdate.GitpodCLIBasePath+"/manifest.json", func(w http.ResponseWriter, r *http.Request) { | ||
mf, err := json.Marshal(selfupdate.Manifest{ | ||
Version: constants.Version, | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
_, _ = w.Write(mf) | ||
}) | ||
}, | ||
Config: AddActiveTestContext(&config.Config{}), | ||
}, | ||
}) | ||
} |
Oops, something went wrong.