Loading .gitlab-ci.yml +1 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ test: version: stage: version image: registry.gitlab.com/juhani/go-semrel-gitlab:v0.16.0-unstable.20180825105527 image: registry.gitlab.com/juhani/go-semrel-gitlab:v0.18.0-alpha.2 script: - release next-version --allow-current > .next-version artifacts: Loading main.go +11 −6 Original line number Diff line number Diff line Loading @@ -147,15 +147,10 @@ func analyzeCommits(c *cli.Context) (*semrel.ReleaseData, error) { } if !isReleaseBranch { // Turn this release a pre-release prV, err := semver.NewPRVersion(currBranch) err = render.SetPreReleaseNumber(releaseData, c) if err != nil { return nil, err } ts, err := semver.NewPRVersion(releaseData.Time.UTC().Format("20060102150405")) if err != nil { return nil, err } releaseData.NextVersion.Pre = []semver.PRVersion{prV, ts} } } return releaseData, nil Loading Loading @@ -511,6 +506,16 @@ func main() { produce normal releases. WARNING: this is an experimental feature.`, EnvVar: "GSG_RELEASE_BRANCHES", }, cli.StringFlag{ Name: "pre-tmpl", Usage: `Pre-release version template. Comma separated list of ID templates.`, EnvVar: "GSG_PRE_TMPL", }, cli.StringFlag{ Name: "build-tmpl", Usage: `Build metadata template. Comma separated list of ID templates.`, EnvVar: "GSG_BUILD_TMPL", }, cli.StringFlag{ Name: "ci-project-path", Usage: "gitlab CI environment variable", Loading pkg/render/render.go +172 −6 Original line number Diff line number Diff line Loading @@ -2,8 +2,19 @@ package render import ( "bytes" "fmt" "os" "strings" "text/template" "time" "github.com/blang/semver" "github.com/juranki/go-semrel/semrel" "github.com/pkg/errors" "github.com/urfave/cli" git "gopkg.in/src-d/go-git.v4" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/object" ) var ( Loading Loading @@ -42,12 +53,27 @@ var ( {{ range .Changes.fix }} - {{ if ne "" .Scope }}**{{ .Scope }}:** {{ end}}{{ .Subject }} ({{ .Hash }}){{ end }}{{ end }}` funcs = template.FuncMap{"date": func() string { return time.Now().Format("2006-01-02") }} preTmpl = []string{ `{{ (env "CI_COMMIT_REF_SLUG") }}`, `{{ seq }}`, } ) func render(releaseInfo interface{}, tmpl string) (string, error) { t := template.Must(template.New("release").Funcs(funcs).Parse(tmpl)) type preReleaseInfo struct { CommitTS time.Time } func render(releaseInfo interface{}, tmpl string, fns template.FuncMap) (string, error) { t := template.New("") if fns != nil { t = t.Funcs(fns) } t, err := t.Parse(tmpl) if err != nil { return "", err } buf := bytes.Buffer{} err := t.Execute(&buf, releaseInfo) err = t.Execute(&buf, releaseInfo) if err != nil { return "", err } Loading @@ -56,10 +82,150 @@ func render(releaseInfo interface{}, tmpl string) (string, error) { // ReleaseNote takes release info object returned by semrel.Release and returns markdown for the release note func ReleaseNote(releaseInfo interface{}) (string, error) { return render(releaseInfo, releaseNoteTmpl) return render(releaseInfo, releaseNoteTmpl, funcs) } // ChangelogEntry takes release info object returned by semrel.Release and returns markdown for the changelog entry func ChangelogEntry(releaseInfo interface{}) (string, error) { return render(releaseInfo, changelogTmpl) return render(releaseInfo, changelogTmpl, funcs) } // SetPreReleaseNumber adds pre- and build parts to the next version of releaseData func SetPreReleaseNumber(releaseData *semrel.ReleaseData, context *cli.Context) error { preTs := parseCommaSeparatedList(context.GlobalString("pre-tmpl")) buildTs := parseCommaSeparatedList(context.GlobalString("build-tmpl")) versions, err := getMatchingVersions(releaseData.NextVersion) if err != nil { return err } fns := template.FuncMap{ "env": os.Getenv, "commitTS": func() time.Time { return releaseData.Time.UTC() }, } if len(preTs) == 0 { preTs = preTmpl } if len(buildTs) > 0 { buildIDs := make([]string, len(buildTs)) for i, buildT := range buildTs { buildStr, err := render(nil, buildT, fns) if err != nil { return errors.Wrapf(err, "formatting %s", buildT) } buildID, err := semver.NewBuildVersion(buildStr) if err != nil { return errors.Wrap(err, "build version tmpl") } buildIDs[i] = buildID } releaseData.NextVersion.Build = buildIDs } if len(preTs) > 0 { preIDs := make([]semver.PRVersion, 0) for _, preT := range preTs { fns["seq"] = getVersionsFun(versions, preIDs) preStr, err := render(nil, preT, fns) if err != nil { return errors.Wrap(err, "pre version tmpl") } preID, err := semver.NewPRVersion(preStr) if err != nil { return errors.Wrap(err, "pre version tmpl") } preIDs = append(preIDs, preID) } releaseData.NextVersion.Pre = preIDs } return nil } func getMatchingVersions(v semver.Version) ([]semver.Version, error) { versions := make([]semver.Version, 0) r, err := git.PlainOpen(".") if err != nil { return nil, err } addIfSemVer := func(sha string, version string) { sv, err := semver.ParseTolerant(version) if err == nil { if v.Major == sv.Major && v.Minor == sv.Minor && v.Patch == sv.Patch { versions = append(versions, sv) } } } tagRefs, err := r.Tags() if err != nil { return nil, err } err = tagRefs.ForEach(func(t *plumbing.Reference) error { addIfSemVer(t.Hash().String(), t.Name().Short()) return nil }) if err != nil { return nil, err } tagObjects, err := r.TagObjects() if err != nil { return nil, err } err = tagObjects.ForEach(func(t *object.Tag) error { addIfSemVer(t.Target.String(), t.Name) return nil }) if err != nil { return nil, err } return versions, nil } func getVersionsFun(versions []semver.Version, preIDs []semver.PRVersion) func() (string, error) { f := func() (string, error) { n := uint64(0) if len(preIDs) == 0 { return "", errors.New("seq cannot be used in first ID of pre number") } for _, v := range versions { if len(v.Pre) > len(preIDs) { if !v.Pre[len(preIDs)].IsNumeric() { continue } if v.Pre[len(preIDs)].VersionNum <= n { continue } match := true for i, p := range preIDs { if p.Compare(v.Pre[i]) != 0 { match = false break } } if match { n = v.Pre[len(preIDs)].VersionNum } } } return fmt.Sprintf("%d", n+1), nil } return f } func parseCommaSeparatedList(s string) []string { if len(strings.TrimSpace(s)) == 0 { return []string{} } ss := strings.Split(s, ",") rv := []string{} for _, t := range ss { rv = append(rv, strings.TrimSpace(t)) } return rv } pre_release_info +3 −3 Original line number Diff line number Diff line RELEASE_URL=https://gitlab.com/api/v4/projects/5767443/jobs/93566147/artifacts/release RELEASE_URL=https://gitlab.com/api/v4/projects/5767443/jobs/95879253/artifacts/release RELEASE_DESC="x86_64 GNU/Linux binary" RELEASE_SHA=3ddda5ff04ca6ddb078c02abf1cc3c9b3b75c2b4 RELEASE_VERSION=0.16.1-unstable.20180831034951 RELEASE_SHA=0cb60e575c5771c19a2316522a5cce697374d219 RELEASE_VERSION=0.18.0-alpha.3 Loading
.gitlab-ci.yml +1 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ test: version: stage: version image: registry.gitlab.com/juhani/go-semrel-gitlab:v0.16.0-unstable.20180825105527 image: registry.gitlab.com/juhani/go-semrel-gitlab:v0.18.0-alpha.2 script: - release next-version --allow-current > .next-version artifacts: Loading
main.go +11 −6 Original line number Diff line number Diff line Loading @@ -147,15 +147,10 @@ func analyzeCommits(c *cli.Context) (*semrel.ReleaseData, error) { } if !isReleaseBranch { // Turn this release a pre-release prV, err := semver.NewPRVersion(currBranch) err = render.SetPreReleaseNumber(releaseData, c) if err != nil { return nil, err } ts, err := semver.NewPRVersion(releaseData.Time.UTC().Format("20060102150405")) if err != nil { return nil, err } releaseData.NextVersion.Pre = []semver.PRVersion{prV, ts} } } return releaseData, nil Loading Loading @@ -511,6 +506,16 @@ func main() { produce normal releases. WARNING: this is an experimental feature.`, EnvVar: "GSG_RELEASE_BRANCHES", }, cli.StringFlag{ Name: "pre-tmpl", Usage: `Pre-release version template. Comma separated list of ID templates.`, EnvVar: "GSG_PRE_TMPL", }, cli.StringFlag{ Name: "build-tmpl", Usage: `Build metadata template. Comma separated list of ID templates.`, EnvVar: "GSG_BUILD_TMPL", }, cli.StringFlag{ Name: "ci-project-path", Usage: "gitlab CI environment variable", Loading
pkg/render/render.go +172 −6 Original line number Diff line number Diff line Loading @@ -2,8 +2,19 @@ package render import ( "bytes" "fmt" "os" "strings" "text/template" "time" "github.com/blang/semver" "github.com/juranki/go-semrel/semrel" "github.com/pkg/errors" "github.com/urfave/cli" git "gopkg.in/src-d/go-git.v4" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/object" ) var ( Loading Loading @@ -42,12 +53,27 @@ var ( {{ range .Changes.fix }} - {{ if ne "" .Scope }}**{{ .Scope }}:** {{ end}}{{ .Subject }} ({{ .Hash }}){{ end }}{{ end }}` funcs = template.FuncMap{"date": func() string { return time.Now().Format("2006-01-02") }} preTmpl = []string{ `{{ (env "CI_COMMIT_REF_SLUG") }}`, `{{ seq }}`, } ) func render(releaseInfo interface{}, tmpl string) (string, error) { t := template.Must(template.New("release").Funcs(funcs).Parse(tmpl)) type preReleaseInfo struct { CommitTS time.Time } func render(releaseInfo interface{}, tmpl string, fns template.FuncMap) (string, error) { t := template.New("") if fns != nil { t = t.Funcs(fns) } t, err := t.Parse(tmpl) if err != nil { return "", err } buf := bytes.Buffer{} err := t.Execute(&buf, releaseInfo) err = t.Execute(&buf, releaseInfo) if err != nil { return "", err } Loading @@ -56,10 +82,150 @@ func render(releaseInfo interface{}, tmpl string) (string, error) { // ReleaseNote takes release info object returned by semrel.Release and returns markdown for the release note func ReleaseNote(releaseInfo interface{}) (string, error) { return render(releaseInfo, releaseNoteTmpl) return render(releaseInfo, releaseNoteTmpl, funcs) } // ChangelogEntry takes release info object returned by semrel.Release and returns markdown for the changelog entry func ChangelogEntry(releaseInfo interface{}) (string, error) { return render(releaseInfo, changelogTmpl) return render(releaseInfo, changelogTmpl, funcs) } // SetPreReleaseNumber adds pre- and build parts to the next version of releaseData func SetPreReleaseNumber(releaseData *semrel.ReleaseData, context *cli.Context) error { preTs := parseCommaSeparatedList(context.GlobalString("pre-tmpl")) buildTs := parseCommaSeparatedList(context.GlobalString("build-tmpl")) versions, err := getMatchingVersions(releaseData.NextVersion) if err != nil { return err } fns := template.FuncMap{ "env": os.Getenv, "commitTS": func() time.Time { return releaseData.Time.UTC() }, } if len(preTs) == 0 { preTs = preTmpl } if len(buildTs) > 0 { buildIDs := make([]string, len(buildTs)) for i, buildT := range buildTs { buildStr, err := render(nil, buildT, fns) if err != nil { return errors.Wrapf(err, "formatting %s", buildT) } buildID, err := semver.NewBuildVersion(buildStr) if err != nil { return errors.Wrap(err, "build version tmpl") } buildIDs[i] = buildID } releaseData.NextVersion.Build = buildIDs } if len(preTs) > 0 { preIDs := make([]semver.PRVersion, 0) for _, preT := range preTs { fns["seq"] = getVersionsFun(versions, preIDs) preStr, err := render(nil, preT, fns) if err != nil { return errors.Wrap(err, "pre version tmpl") } preID, err := semver.NewPRVersion(preStr) if err != nil { return errors.Wrap(err, "pre version tmpl") } preIDs = append(preIDs, preID) } releaseData.NextVersion.Pre = preIDs } return nil } func getMatchingVersions(v semver.Version) ([]semver.Version, error) { versions := make([]semver.Version, 0) r, err := git.PlainOpen(".") if err != nil { return nil, err } addIfSemVer := func(sha string, version string) { sv, err := semver.ParseTolerant(version) if err == nil { if v.Major == sv.Major && v.Minor == sv.Minor && v.Patch == sv.Patch { versions = append(versions, sv) } } } tagRefs, err := r.Tags() if err != nil { return nil, err } err = tagRefs.ForEach(func(t *plumbing.Reference) error { addIfSemVer(t.Hash().String(), t.Name().Short()) return nil }) if err != nil { return nil, err } tagObjects, err := r.TagObjects() if err != nil { return nil, err } err = tagObjects.ForEach(func(t *object.Tag) error { addIfSemVer(t.Target.String(), t.Name) return nil }) if err != nil { return nil, err } return versions, nil } func getVersionsFun(versions []semver.Version, preIDs []semver.PRVersion) func() (string, error) { f := func() (string, error) { n := uint64(0) if len(preIDs) == 0 { return "", errors.New("seq cannot be used in first ID of pre number") } for _, v := range versions { if len(v.Pre) > len(preIDs) { if !v.Pre[len(preIDs)].IsNumeric() { continue } if v.Pre[len(preIDs)].VersionNum <= n { continue } match := true for i, p := range preIDs { if p.Compare(v.Pre[i]) != 0 { match = false break } } if match { n = v.Pre[len(preIDs)].VersionNum } } } return fmt.Sprintf("%d", n+1), nil } return f } func parseCommaSeparatedList(s string) []string { if len(strings.TrimSpace(s)) == 0 { return []string{} } ss := strings.Split(s, ",") rv := []string{} for _, t := range ss { rv = append(rv, strings.TrimSpace(t)) } return rv }
pre_release_info +3 −3 Original line number Diff line number Diff line RELEASE_URL=https://gitlab.com/api/v4/projects/5767443/jobs/93566147/artifacts/release RELEASE_URL=https://gitlab.com/api/v4/projects/5767443/jobs/95879253/artifacts/release RELEASE_DESC="x86_64 GNU/Linux binary" RELEASE_SHA=3ddda5ff04ca6ddb078c02abf1cc3c9b3b75c2b4 RELEASE_VERSION=0.16.1-unstable.20180831034951 RELEASE_SHA=0cb60e575c5771c19a2316522a5cce697374d219 RELEASE_VERSION=0.18.0-alpha.3