Skip to content

Commit

Permalink
Merge pull request #11 from dpastoor/feat/improve-versioning
Browse files Browse the repository at this point in the history
Feat/improve versioning
  • Loading branch information
dpastoor authored Oct 27, 2022
2 parents 02a467b + 2b16399 commit e01a0a6
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 22 deletions.
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

0 comments on commit e01a0a6

Please sign in to comment.