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

Feat/improve versioning #11

Merged
merged 3 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
35 changes: 24 additions & 11 deletions cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ type installOpts struct {
progress bool
}

func newInstall(installOpts installOpts, release string) error {
func newInstall(installOpts installOpts, release string) (error, string) {
iv, err := config.GetInstalledVersions()
if err != nil && !errors.Is(err, os.ErrNotExist) {
return err
return err, ""
}
if release == "" {
client := gh.NewClient(os.Getenv("GITHUB_PAT"))
releases, err := gh.GetReleases(client, false)
releases, err := gh.GetReleases(client, 100)
if err != nil {
return err
return err, ""
}
versions := []string{}
for _, r := range releases {
Expand All @@ -52,30 +52,43 @@ func newInstall(installOpts installOpts, release string) error {
},
}, &release, survey.WithPageSize(10))
if err != nil {
return err
return err, ""
}
}
if release == "latest" {

// github's latest release is literally their latest release,
// not the latest tagged version
if release == "release" {
client := gh.NewClient(os.Getenv("GITHUB_PAT"))
latestRelease, err := gh.GetLatestRelease(client)
if err != nil {
return err
return err, ""
}
release = latestRelease.GetTagName()
}

if release == "latest" {
client := gh.NewClient(os.Getenv("GITHUB_PAT"))
releases, err := gh.GetReleases(client, 1)
if err != nil {
return err, ""
}
release = releases[0].GetTagName()
}

_, ok := iv[release]
if ok {
log.Infof("quarto version %s is already installed\n", release)
return nil
return nil, release
}
log.Info("attempting to install quarto version: ", release)
res, err := pipeline.DownloadReleaseVersion(release, runtime.GOOS, installOpts.progress)
if err != nil {
return err
return err, ""
}
log.Infof("new quarto version %s installed\n", release)
log.Debugf("new quarto version installed to %s\n", res)
return nil
return nil, release
}

func setInstallOpts(installOpts *installOpts) {
Expand Down Expand Up @@ -112,7 +125,7 @@ func newInstallCmd() *installCmd {
wg.Add(1)
go func(errc <-chan error, release string) {
defer wg.Done()
err := newInstall(root.opts, release)
err, _ := newInstall(root.opts, release)
errChan <- err
}(errChan, arg)
}
Expand Down
20 changes: 17 additions & 3 deletions cmd/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,26 @@ type lsCmd struct {

type lsOpts struct {
remote bool
num int
}

func newLs(lsOpts lsOpts) error {
if lsOpts.remote {
client := gh.NewClient(os.Getenv("GITHUB_PAT"))
releases, err := gh.GetReleases(client, false)
releases, err := gh.GetReleases(client, lsOpts.num)
if err != nil {
return err
}
fmt.Println("version | release date | description")
fmt.Println("version | release date | description | type")
for _, r := range releases {
createdAt := r.GetCreatedAt()
fmt.Printf("%s | %s | %s\n", r.GetTagName(), createdAt.Format("2006-01-02"), r.GetName())
var releaseType string
if r.GetPrerelease() {
releaseType = "pre-release"
} else {
releaseType = "release"
}
fmt.Printf("%s | %s | %s | %s \n", r.GetTagName(), createdAt.Format("2006-01-02"), r.GetName(), releaseType)
}
} else {
entries, err := os.ReadDir(config.GetPathToVersionsDir())
Expand All @@ -43,6 +50,10 @@ func newLs(lsOpts lsOpts) error {
if err != nil {
return err
}
if len(entries) < lsOpts.num {
lsOpts.num = len(entries)
}
entries = entries[:lsOpts.num-1]
// TODO: replace with actual table
fmt.Println("version | install time")
fmt.Println("--------------------------------")
Expand Down Expand Up @@ -78,6 +89,7 @@ func newLs(lsOpts lsOpts) error {

func setLsOpts(lsOpts *lsOpts) {
lsOpts.remote = viper.GetBool("remote")
lsOpts.num = viper.GetInt("number")
}

func (opts *lsOpts) Validate() error {
Expand Down Expand Up @@ -108,6 +120,8 @@ func newLsCmd() *lsCmd {
}
cmd.Flags().Bool("remote", false, "list remote versions")
viper.BindPFlag("remote", cmd.Flags().Lookup("remote"))
cmd.Flags().IntP("number", "n", 10, "number of versions to list")
viper.BindPFlag("number", cmd.Flags().Lookup("number"))
root.cmd = cmd
return root
}
66 changes: 61 additions & 5 deletions cmd/use.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import (
"path/filepath"
"runtime"
"sort"
"strings"

"github.com/AlecAivazis/survey/v2"
"github.com/coreos/go-semver/semver"
"github.com/dpastoor/qvm/internal/config"
"github.com/dpastoor/qvm/internal/gh"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/exp/maps"
)

Expand All @@ -21,6 +25,7 @@ type useCmd struct {
}

type useOpts struct {
install bool
}

func newUse(useOpts useOpts, version string) error {
Expand All @@ -29,12 +34,54 @@ func newUse(useOpts useOpts, version string) error {
return err
}
versions := maps.Keys(iv)
sort.Sort(sort.Reverse(sort.StringSlice(versions)))
if len(iv) == 0 {
var semVersions semver.Versions
// sorting has some issues given how the character values will present individually
// for example a high value double digit patch version will be sorted before a lower
// value triple digit patch version. For example, sorting shows ordering like:
// v1.2.89 v1.2.237 v1.2.112 v1.1.84 v1.1.251 v1.1.189
// where .89 is > 237
// using go-semver this works
// as will get 1.2.237 1.2.112 1.2.89 1.1.251 1.1.189 1.1.168 1.1.84
for _, v := range versions {
ver, err := semver.NewVersion(strings.TrimPrefix(v, "v"))
if err != nil {
// we're just going to warn rather than error right now in case some
// releases end up not following semver and would rather the tool not blow up
log.Errorf("could not parse semver value for %s with err %s\n ", v, err)
continue
}
semVersions = append(semVersions, ver)
}
sort.Sort(sort.Reverse(semVersions))
// note this could be a bug if ever we do get nonparseable versions thrown out above
// will cross that bridge if we get there
for i, v := range semVersions {
versions[i] = "v" + v.String()
}
// convert back to string for later options
if len(iv) == 0 && !useOpts.install {
return errors.New("no installed versions found, please install a version first")
}
client := gh.NewClient(os.Getenv("GITHUB_PAT"))
if version == "release" {
latestRelease, err := gh.GetLatestRelease(client)
if err != nil {
return err
}
version = latestRelease.GetTagName()
}
if version == "latest" {
version = versions[0]
if useOpts.install {
// this will install further down if the version isn't already installed
repo, err := gh.GetReleases(client, 1)
if err != nil {
return err
}
version = repo[0].GetTagName()
} else {
version = versions[0]
}
// add back the v we trimmed for semver
}
if version == "" {
// not worried about an error here as an active version of
Expand All @@ -56,7 +103,14 @@ func newUse(useOpts useOpts, version string) error {
}
quartopath, ok := iv[version]
if !ok {
return fmt.Errorf("version %s not found", version)
if useOpts.install {
err, version = newInstall(installOpts{progress: true}, version)
if err != nil {
return err
}
} else {
return fmt.Errorf("version %s not found", version)
}
}
err = os.MkdirAll(config.GetPathToActiveBinDir(), 0755)
if err != nil {
Expand All @@ -82,7 +136,7 @@ func newUse(useOpts useOpts, version string) error {
}

func setUseOpts(useOpts *useOpts) {

useOpts.install = viper.GetBool("install")
}

func (opts *useOpts) Validate() error {
Expand Down Expand Up @@ -115,6 +169,8 @@ func newUseCmd() *useCmd {
return nil
},
}
cmd.Flags().Bool("install", false, "install the version if not already installed")
viper.BindPFlag("install", cmd.Flags().Lookup("install"))
root.cmd = cmd
return root
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.18
require (
github.com/AlecAivazis/survey/v2 v2.3.5-0.20220530090844-e47352f91434
github.com/adrg/xdg v0.4.0
github.com/coreos/go-semver v0.3.0
github.com/dustin/go-humanize v1.0.0
github.com/google/go-github/v44 v44.1.0
github.com/mholt/archiver/v4 v4.0.0-alpha.6.0.20220421032531-8a97d87612e9
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
Expand Down
20 changes: 17 additions & 3 deletions internal/gh/releases.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,19 @@ func GetLatestRelease(client *github.Client) (*github.RepositoryRelease, error)
return rel, err
}

func GetReleases(client *github.Client, paginate bool) ([]*github.RepositoryRelease, error) {
opts := &github.ListOptions{PerPage: 50}
func GetReleases(client *github.Client, n int) ([]*github.RepositoryRelease, error) {
// max of 50 per page
perPage := 50
remaining := n - perPage
if n < 50 {
remaining = 0
perPage = n
}
var releases []*github.RepositoryRelease
opts := &github.ListOptions{PerPage: perPage}
for {
start := time.Now()
log.Tracef("perpage: %d, remaining: %d", opts.PerPage, remaining)
rel, resp, err := client.Repositories.ListReleases(
context.Background(),
"quarto-dev",
Expand All @@ -48,9 +56,15 @@ func GetReleases(client *github.Client, paginate bool) ([]*github.RepositoryRele
}
releases = append(releases, rel...)
log.Tracef("repository release paginator: %s, page: %d", time.Since(start), resp.NextPage)
if !paginate || resp.NextPage == 0 {
if remaining <= 0 || resp.NextPage == 0 {
break
}
if remaining <= perPage {
opts.PerPage = remaining
remaining = 0
} else {
remaining -= perPage
}
opts.Page = resp.NextPage
}
return releases, nil
Expand Down