Skip to content

Commit

Permalink
Merge pull request #1505 from rsteube/gh-release-version
Browse files Browse the repository at this point in the history
gh: release create - complete next semantic version
  • Loading branch information
rsteube authored Jan 29, 2023
2 parents 23b38ba + 1dd76fd commit fc79710
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 1 deletion.
17 changes: 17 additions & 0 deletions completers/gh_completer/cmd/action/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"time"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bin/pkg/actions/number"
"github.com/rsteube/carapace-bin/pkg/styles"
"github.com/rsteube/carapace-bin/pkg/util"
"github.com/rsteube/carapace/pkg/style"
Expand Down Expand Up @@ -37,6 +38,22 @@ type releaseQuery struct {
}
}

func ActionNextReleases(cmd *cobra.Command) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
var queryResult releaseQuery
return GraphQlAction(cmd, `repository(owner: $owner, name: $repo) { releases(first: 100, orderBy: {direction: DESC, field: CREATED_AT}) { edges { node { createdAt isPrerelease name tag { name } } } } }`, &queryResult, func() carapace.Action {
releases := queryResult.Data.Repository.Releases.Edges
vals := make([]string, 0, len(releases))
for _, release := range releases {
if release.Node.Tag.Name != "" {
vals = append(vals, release.Node.Tag.Name)
}
}
return number.ActionSemanticVersions(vals...).Style(styles.Git.Tag)
})
})
}

func ActionReleases(cmd *cobra.Command) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
var queryResult releaseQuery
Expand Down
2 changes: 1 addition & 1 deletion completers/gh_completer/cmd/release_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func init() {
})

carapace.Gen(release_createCmd).PositionalCompletion(
action.ActionReleases(release_createCmd),
action.ActionNextReleases(release_createCmd),
)
carapace.Gen(release_createCmd).PositionalAnyCompletion(carapace.ActionFiles())
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/rsteube/carapace-spec v0.5.3
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
golang.org/x/mod v0.7.0
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
Expand Down
72 changes: 72 additions & 0 deletions pkg/actions/number/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package number

import (
"fmt"
"regexp"
"sort"
"strconv"
"strings"

"github.com/rsteube/carapace"
"golang.org/x/mod/semver"
)

// ActionSemanticVersions completes the next semantic version based on the given existing versions.
//
// v0.20.4 (next patch version)
// v0.21.0 (next minor version)
func ActionSemanticVersions(versions ...string) carapace.Action {
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if len(versions) == 0 {
versions = append(versions, "v0.0.0")
}

withoutPrefix := make(map[string]bool, 0)
for index, version := range versions {
switch {
case semver.IsValid(version):
// valid
case semver.IsValid("v" + version):
// support versions without 'v' prefix as well
withoutPrefix[version] = true
versions[index] = "v" + version
default:
// skip invalid
versions[index] = ""
}
}

sort.Sort(semver.ByVersion(versions))
canonical := semver.Canonical(versions[len(versions)-1])
if canonical == "" {
return carapace.ActionMessage("invalid version %#v", versions[0])
}

prefix := "v"
if _, ok := withoutPrefix[strings.TrimPrefix(canonical, "v")]; ok {
prefix = ""
}

r := regexp.MustCompile(`^v(?P<major>[0-9]+)\.(?P<minor>[0-9]+)\.(?P<patch>[0-9]+)`)
vals := make([]string, 0)
if matches := r.FindStringSubmatch(canonical); matches != nil {
// valid format ensured by semver.Canonical
major, _ := strconv.Atoi(matches[1])
minor, _ := strconv.Atoi(matches[2])
patch, _ := strconv.Atoi(matches[3])

if semver.Prerelease(canonical) != "" {
vals = append(vals,
fmt.Sprintf("%v%v.%v.%v", prefix, major, minor, patch), "next version",
)
} else {
vals = append(vals,
fmt.Sprintf("%v%v.%v.%v", prefix, major+1, 0, 0), "next major version",
fmt.Sprintf("%v%v.%v.%v", prefix, major, minor+1, 0), "next minor version",
fmt.Sprintf("%v%v.%v.%v", prefix, major, minor, patch+1), "next patch version",
)
}
}
return carapace.ActionValuesDescribed(vals...)
})
}

0 comments on commit fc79710

Please sign in to comment.