Skip to content
Open
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ autotag --strict-match

- Use `-T/--pre-release-timestmap=` to append **timestamp** to the version. Allowed timetstamp
formats are `datetime` (YYYYMMDDHHMMSS) or `epoch` (UNIX epoch timestamp in seconds).

- Use `--pre-release-number` to append pre-release number to the version. Pre-release is also mentioned in the [SemVer](https://semver.org/#spec-item-9) spec. Note: `--pre-release-number` is used only when option `--pre-release-timestmap` isn't enabled.

### Build metadata

Expand Down
50 changes: 48 additions & 2 deletions autotag.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ type GitRepoConfig struct {
// v1.2.3-pre.1499308568
PreReleaseTimestampLayout string

// PreReleaseNumber is the optional flag that's used to tell program append a
// build number to the git tag as second part of prerelease.
//
// Assuming PreReleaseName is set to `pre`, the PreReleaseBuildNumber is appended to
// that value separated by a period (`.`):
//
// v1.2.3-pre.1
PreReleaseNumber bool

// BuildMetadata is an optional string appended by a plus sign and a series of dot separated
// identifiers immediately following the patch or pre-release version. Identifiers MUST comprise
// only ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Build metadata
Expand Down Expand Up @@ -146,11 +155,13 @@ type GitRepo struct {
branch string
branchID string // commit id of the branch latest commit (where we will apply the tag)

curPreReleaseVer *version.Version
latestTagVersion *version.Version
latestTagCommit *git.Commit

preReleaseName string
preReleaseTimestampLayout string
preReleaseNumber bool
buildMetadata string

scheme string
Expand Down Expand Up @@ -214,6 +225,7 @@ func NewRepo(cfg GitRepoConfig) (*GitRepo, error) {
branch: cfg.Branch,
preReleaseName: cfg.PreReleaseName,
preReleaseTimestampLayout: cfg.PreReleaseTimestampLayout,
preReleaseNumber: cfg.PreReleaseNumber,
buildMetadata: cfg.BuildMetadata,
scheme: cfg.Scheme,
prefix: cfg.Prefix,
Expand Down Expand Up @@ -310,6 +322,13 @@ func (r *GitRepo) parseTags() error {
r.latestTagCommit = versions[version]
}

// stamps latest tag for pre-release
if r.preReleaseName != "" && version.Prerelease() != "" && r.curPreReleaseVer == nil {
if strings.HasPrefix(version.Prerelease(), fmt.Sprintf("%s.", r.preReleaseName)) {
r.curPreReleaseVer = version
}
}

if len(version.Prerelease()) == 0 {
r.currentVersion = version
r.currentTag = versions[version]
Expand Down Expand Up @@ -365,7 +384,7 @@ func (r *GitRepo) retrieveBranchInfo() error {
return nil
}

func preReleaseVersion(v *version.Version, name, tsLayout string) (*version.Version, error) {
func preReleaseVersion(v, curPrereleaseVer *version.Version, name, tsLayout string, autoIncrease bool) (*version.Version, error) {
if len(name) == 0 && len(tsLayout) == 0 {
return v, nil
}
Expand Down Expand Up @@ -405,6 +424,33 @@ func preReleaseVersion(v *version.Version, name, tsLayout string) (*version.Vers
if _, err := buf.WriteString(timestamp); err != nil {
return nil, err
}
} else {
if len(name) > 0 && autoIncrease {
// Write the `.` character
if buf.Len() > 0 {
if _, err := buf.WriteString("."); err != nil {
return nil, err
}
}

prereleaseNumber := "1"
if curPrereleaseVer != nil {
prerelease := curPrereleaseVer.Prerelease()
prereleaseParts := strings.Split(prerelease, ".")
if len(prereleaseParts) == 2 {
currentPrereleaseNumber, err := strconv.ParseUint(prereleaseParts[1], 10, 64)
if err != nil {
return nil, fmt.Errorf("prerelease build number must be a unsigned integer")
}

prereleaseNumber = strconv.FormatUint(currentPrereleaseNumber+1, 10)
}
}

if _, err := buf.WriteString(prereleaseNumber); err != nil {
return nil, err
}
}
}

verStr := fmt.Sprintf("%s-%s", v.String(), buf.String())
Expand Down Expand Up @@ -466,7 +512,7 @@ func (r *GitRepo) calcVersion() error {

// append pre-release-name and/or pre-release-timestamp to the version
if len(r.preReleaseName) > 0 || len(r.preReleaseTimestampLayout) > 0 {
if r.newVersion, err = preReleaseVersion(r.newVersion, r.preReleaseName, r.preReleaseTimestampLayout); err != nil {
if r.newVersion, err = preReleaseVersion(r.newVersion, r.curPreReleaseVer, r.preReleaseName, r.preReleaseTimestampLayout, r.preReleaseNumber); err != nil {
return err
}
}
Expand Down
2 changes: 2 additions & 0 deletions autotag/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Options struct {
RepoPath string `short:"r" long:"repo" description:"Path to the repo" default:"./" `
PreReleaseName string `short:"p" long:"pre-release-name" description:"create a pre-release tag"`
PreReleaseTimestamp string `short:"T" long:"pre-release-timestamp" description:"create a pre-release tag and append a timestamp (can be: datetime|epoch)"`
PreReleaseNumber bool `long:"pre-release-number" description:"create a pre-release tag and append a pre-release number"`
BuildMetadata string `short:"m" long:"build-metadata" description:"optional SemVer build metadata to append to the version with '+' character"`
Scheme string `short:"s" long:"scheme" description:"The commit message scheme to use (can be: autotag|conventional)" default:"autotag"`
NoVersionPrefix bool `short:"e" long:"empty-version-prefix" description:"Do not prepend v to version tag"`
Expand Down Expand Up @@ -46,6 +47,7 @@ func main() {
Branch: opts.Branch,
PreReleaseName: opts.PreReleaseName,
PreReleaseTimestampLayout: opts.PreReleaseTimestamp,
PreReleaseNumber: opts.PreReleaseNumber,
BuildMetadata: opts.BuildMetadata,
Scheme: opts.Scheme,
Prefix: !opts.NoVersionPrefix,
Expand Down
79 changes: 79 additions & 0 deletions autotag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type testRepoSetup struct {
// (optional) the prerelease timestamp format to use, eg: "epoch". If not set, no prerelease timestamp will be used
preReleaseTimestampLayout string

// (optional) will optional append prerelease number in second part of prerelease (default: false)
preReleaseNumber bool

// (optional) build metadata to append to the version
buildMetadata string

Expand Down Expand Up @@ -103,6 +106,7 @@ func newTestRepo(t *testing.T, setup testRepoSetup) (GitRepo, error) {
Branch: branch,
PreReleaseName: setup.preReleaseName,
PreReleaseTimestampLayout: setup.preReleaseTimestampLayout,
PreReleaseNumber: setup.preReleaseNumber,
BuildMetadata: setup.buildMetadata,
Scheme: setup.scheme,
Prefix: !setup.disablePrefix,
Expand Down Expand Up @@ -437,6 +441,81 @@ func TestPatch(t *testing.T) {
}
}

func TestPrereleaseNumberFirstTime(t *testing.T) {
r, err := newTestRepo(t, testRepoSetup{
preReleaseNumber: true,
preReleaseName: "dev",
initialTag: "v1.0.1",
})
if err != nil {
t.Fatal("Error creating repo: ", err)
}
defer cleanupTestRepo(t, r.repo)

v := r.LatestVersion()

if v != "1.0.2-dev.1" {
t.Fatalf("Prerelease number bump failed expected '1.0.2-dev.1' got '%s' \n", v)
}
}

func TestPrereleaseNumber(t *testing.T) {
r, err := newTestRepo(t, testRepoSetup{
preReleaseNumber: true,
preReleaseName: "dev",
initialTag: "v1.0.1",
extraTags: []string{"v1.0.2-dev.1"},
})
if err != nil {
t.Fatal("Error creating repo: ", err)
}
defer cleanupTestRepo(t, r.repo)

v := r.LatestVersion()

if v != "1.0.2-dev.2" {
t.Fatalf("Prerelease number bump failed expected '1.0.2-dev.2' got '%s' \n", v)
}
}

func TestPrereleaseNumberWithExtraTags(t *testing.T) {
r, err := newTestRepo(t, testRepoSetup{
preReleaseNumber: true,
preReleaseName: "dev",
initialTag: "v1.0.1",
extraTags: []string{"v1.0.2-dev.1", "v1.0.2-next.1"},
})
if err != nil {
t.Fatal("Error creating repo: ", err)
}
defer cleanupTestRepo(t, r.repo)

v := r.LatestVersion()

if v != "1.0.2-dev.2" {
t.Fatalf("Prerelease number bump failed expected '1.0.2-dev.2' got '%s' \n", v)
}
}

func TestPrereleaseNumberWithNewVersion(t *testing.T) {
r, err := newTestRepo(t, testRepoSetup{
preReleaseNumber: true,
preReleaseName: "dev",
initialTag: "v1.0.1",
extraTags: []string{"v1.0.2-dev.1", "v1.0.2"},
})
if err != nil {
t.Fatal("Error creating repo: ", err)
}
defer cleanupTestRepo(t, r.repo)

v := r.LatestVersion()

if v != "1.0.3-dev.1" {
t.Fatalf("Prerelease number bump failed expected '1.0.3-dev.1' got '%s' \n", v)
}
}

func TestBuildNumberFirstTime(t *testing.T) {
r, err := newTestRepo(t, testRepoSetup{
buildNumber: true,
Expand Down