Skip to content

feat: Add tag-format support to provider #11

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
72 changes: 71 additions & 1 deletion pkg/provider/github.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package provider

import (
"bytes"
"context"
"errors"
"fmt"
"log"
"os"
"regexp"
"strconv"
"strings"
"text/template"
"time"

"github.com/Masterminds/semver/v3"
Expand All @@ -17,14 +20,22 @@ import (
"golang.org/x/oauth2"
)

// Taken from https://github.com/Masterminds/semver/blob/master/version.go licence by MIT
const semVerRegex string = `(?P<version>v?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:\.(0|[1-9]\d*))?` +
`(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?` +
`(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)`

var PVERSION = "dev"
var DEFAULT_TAG_FORMAT = "{{.Version}}" // no "v" prefix because Version is asumed to have v as a prefix if strip_v_tag_prefix is false

type GitHubRepository struct {
owner string
repo string
stripVTagPrefix bool
client *github.Client
compareCommits bool
tagFormat *template.Template
tagRegex *regexp.Regexp
}

func (repo *GitHubRepository) Init(config map[string]string) error {
Expand Down Expand Up @@ -70,7 +81,29 @@ func (repo *GitHubRepository) Init(config map[string]string) error {
repo.compareCommits = true
}

tagFormat := DEFAULT_TAG_FORMAT
if config["tag_format"] != "" {
tagFormat = config["tag_format"]
}

var err error
repo.tagFormat, err = template.New("tagFormat").Funcs(template.FuncMap{
"env": func(key string) string {
if strings.HasPrefix(key, "SEMREL_") {
return os.Getenv(key)
}
return ""
},
}).Parse(tagFormat)
if err != nil {
return fmt.Errorf("failed to parse tag_format: %w", err)
}

var buf bytes.Buffer
repo.tagFormat.Execute(&buf, map[string]string{"Version": semVerRegex})

repo.tagRegex = regexp.MustCompile(buf.String())

stripVTagPrefix := config["strip_v_tag_prefix"]
repo.stripVTagPrefix, err = strconv.ParseBool(stripVTagPrefix)

Expand Down Expand Up @@ -166,10 +199,18 @@ func (repo *GitHubRepository) GetReleases(rawRe string) ([]*semrel.Release, erro
return nil, err
}
for _, r := range refs {
reformatForSemver := false
tag := strings.TrimPrefix(r.GetRef(), "refs/tags/")
if rawRe != "" && !re.MatchString(tag) {
continue
}

if !repo.tagRegex.MatchString(tag) {
continue
} else {
reformatForSemver = true
}

objType := r.Object.GetType()
if objType != "commit" && objType != "tag" {
continue
Expand All @@ -186,6 +227,16 @@ func (repo *GitHubRepository) GetReleases(rawRe string) ([]*semrel.Release, erro
}
foundSha = resTag.Object.GetSHA()
}

if reformatForSemver {
matches := mustExtractNamedGroups(repo.tagRegex, tag)
tag = matches["version"]
if tag == "" {
log.Printf("Skipping tag %s as it does not have a version or tag format does not contain a named capture group 'version'", tag)
continue
}
}

version, err := semver.NewVersion(tag)
if err != nil {
continue
Expand All @@ -207,7 +258,10 @@ func (repo *GitHubRepository) CreateRelease(release *provider.CreateReleaseConfi
prefix = ""
}

tag := prefix + release.NewVersion
var buf bytes.Buffer
repo.tagFormat.Execute(&buf, map[string]string{"Version": prefix + release.NewVersion})

tag := buf.String()
isPrerelease := release.Prerelease || semver.MustParse(release.NewVersion).Prerelease() != ""

if release.Branch != release.SHA {
Expand Down Expand Up @@ -240,3 +294,19 @@ func (repo *GitHubRepository) Name() string {
func (repo *GitHubRepository) Version() string {
return PVERSION
}

// ExtractNamedGroups returns a map of named capture groups
func mustExtractNamedGroups(re *regexp.Regexp, input string) map[string]string {
result := make(map[string]string)
match := re.FindStringSubmatch(input)
if match == nil {
return result
}

for i, name := range re.SubexpNames() {
if i > 0 && name != "" { // Ignore index 0 (whole match) and unnamed groups
result[name] = match[i]
}
}
return result
}