Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Commit

Permalink
Add new strategy staticMarker (#9)
Browse files Browse the repository at this point in the history
Description
===========

This new strategy won't auto increment the normal part of the version as
`semver` or `semver2` would do. Instead the whole normal part of the
version is taken from a `marker` tag. Other metadata information for
prerelease versions are generated in a similar fashion than done in the
`semver` strategies but not based on the latest release tag but also on
the marker tag.

One can define two marker tags in the project.

* `ci-0.0.0`
* `release-0.0.0`

The prefix can not be configured at the moment. The version strategy
will look for these markers and determine the normal of the generated
version. We have two different markers depending on the current release
cycle. We can configure to use a specific marker based on the current
git branch. This can be configured with the `releaseBranchPattern`
property which has a default value of `/(^release\/.*|^master$)/`. Which
means if the current branch is named `master` or starts with `release/`
then use the normal from the `release-*` marker tag. If not use the ci
marker. This allows to bump the ci version to the next to be released
version for development when the release process is kicked off in a
sidebranch. To illustrate this:

```
         *     branch: 'develop', version: '0.2.0-develop.2
        /|
       ◊ |     branch: 'master', version: '0.1.0', tag: 'v0.1.0,
       | |
       * |     branch: 'master', version: '0.1.0-master.1, distance: 1
       | |
       | *     branch: 'develop', version: '0.2.0-develop.1
        \|
         ◊     branch: 'develop', version: '0.0.0', tag: 'release-0.1.0', ci-0.2.0,
```

Staging and production build generation works as before. Staging builds
will increment based on the previous staging version.

This patch also adds a new configuration property which allows to
configure which branch(es) are the main development branches. This
information is used to construct the snapshot prerelease metadata.

A snapshot version gets constructed with the normal version part +
encoded branchname + counter.

The branchname comes in two flavors.
If it is a main branch (`master`, `develop`) by default it won't be
prefixed with `branch.` (depending on the semver strategy)
Now it's possible to provide a patter for this check

`mainBranchPattern` the default value is `/(^master$|^develop$)/`

Changes
=======

* ![ADD] `staticMarker` version strategy
  • Loading branch information
Larusso authored Sep 28, 2020
1 parent 1bc0db8 commit 4b16e67
Show file tree
Hide file tree
Showing 13 changed files with 563 additions and 80 deletions.

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/main/groovy/wooga/gradle/version/VersionConsts.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class VersionConsts {
static final String GIT_ROOT_PROPERTY = "git.root"
static final String UNINITIALIZED_VERSION = '0.1.0-dev.0.uninitialized'

static final String DEFAULT_MAIN_BRANCH_PATTERN = /(^master$|^develop$)/
static final String DEFAULT_RELEASE_BRANCH_PATTERN = /(^release\/.*|^master$)/

static final VersionScheme VERSION_SCHEME_DEFAULT = VersionScheme.semver
static final VersionCodeScheme VERSION_CODE_SCHEME_DEFAULT = VersionCodeScheme.none

Expand All @@ -43,4 +46,10 @@ class VersionConsts {

static final String VERSION_STAGE_OPTION = "versionBuilder.stage"
static final String VERSION_STAGE_ENV_VAR = "VERSION_BUILDER_STAGE"

static final String RELEASE_BRANCH_PATTERN_OPTION = "versionBuilder.releaseBranchPattern"
static final String RELEASE_BRANCH_PATTERN_ENV_VAR = "VERSION_BUILDER_RELEASE_BRANCH_PATTERN"

static final String MAIN_BRANCH_PATTERN_OPTION = "versionBuilder.mainBranchPattern"
static final String MAIN_BRANCH_PATTERN_ENV_VAR = "VERSION_BUILDER_MAIN_BRANCH_PATTERN"
}
12 changes: 12 additions & 0 deletions src/main/groovy/wooga/gradle/version/VersionPluginExtension.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ interface VersionPluginExtension {
void setVersionCodeOffset(Integer value)
void setVersionCodeOffset(Provider<Integer> value)

Property<String> getReleaseBranchPattern()
void releaseBranchPattern(String value)
void releaseBranchPattern(Provider<String> value)
void setReleaseBranchPattern(String value)
void setReleaseBranchPattern(Provider<String> value)

Property<String> getMainBranchPattern()
void mainBranchPattern(String value)
void mainBranchPattern(Provider<String> value)
void setMainBranchPattern(String value)
void setMainBranchPattern(Provider<String> value)

Property<Grgit> getGit()

Provider<ReleaseVersion> getVersion()
Expand Down
2 changes: 1 addition & 1 deletion src/main/groovy/wooga/gradle/version/VersionScheme.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
package wooga.gradle.version

enum VersionScheme {
semver, semver2
semver, semver2, staticMarker
}


Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import wooga.gradle.version.VersionConsts
import wooga.gradle.version.VersionPluginExtension
import wooga.gradle.version.strategies.SemverV1Strategies
import wooga.gradle.version.strategies.SemverV2Strategies
import wooga.gradle.version.strategies.StaticMarkerStrategies

class DefaultVersionPluginExtension implements VersionPluginExtension {

Expand All @@ -55,6 +56,8 @@ class DefaultVersionPluginExtension implements VersionPluginExtension {
final TagStrategy tagStrategy = new TagStrategy()
final Provider<ReleaseVersion> version
final Provider<Integer> versionCode
final Property<String> releaseBranchPattern
final Property<String> mainBranchPattern

@Override
void versionScheme(VersionScheme value) {
Expand Down Expand Up @@ -136,6 +139,46 @@ class DefaultVersionPluginExtension implements VersionPluginExtension {
versionCodeOffset.set(value)
}

@Override
void releaseBranchPattern(String value) {
setReleaseBranchPattern(value)
}

@Override
void releaseBranchPattern(Provider<String> value) {
setReleaseBranchPattern(value)
}

@Override
void setReleaseBranchPattern(String value) {
releaseBranchPattern.set(value)
}

@Override
void setReleaseBranchPattern(Provider<String> value) {
releaseBranchPattern.set(value)
}

@Override
void mainBranchPattern(String value) {
setMainBranchPattern(value)
}

@Override
void mainBranchPattern(Provider<String> value) {
setMainBranchPattern(value)
}

@Override
void setMainBranchPattern(String value) {
mainBranchPattern.set(value)
}

@Override
void setMainBranchPattern(Provider<String> value) {
mainBranchPattern.set(value)
}

DefaultVersionPluginExtension(Project project) {
this.project = project
versionScheme = project.objects.property(VersionScheme)
Expand All @@ -148,21 +191,59 @@ class DefaultVersionPluginExtension implements VersionPluginExtension {
preReleaseStrategy = project.objects.property(VersionStrategy)
finalStrategy = project.objects.property(VersionStrategy)
defaultStrategy = project.objects.property(VersionStrategy)
releaseBranchPattern = project.objects.property(String)
mainBranchPattern = project.objects.property(String)

snapshotStrategy.set(versionScheme.map({ scheme ->
scheme == VersionScheme.semver2 ? SemverV2Strategies.SNAPSHOT : SemverV1Strategies.SNAPSHOT
switch (scheme) {
case VersionScheme.semver2:
SemverV2Strategies.SNAPSHOT
break;
case VersionScheme.staticMarker:
StaticMarkerStrategies.SNAPSHOT
break
default:
SemverV1Strategies.SNAPSHOT
}
}))

developmentStrategy.set(versionScheme.map({ scheme ->
scheme == VersionScheme.semver2 ? SemverV2Strategies.DEVELOPMENT : SemverV1Strategies.DEVELOPMENT
switch (scheme) {
case VersionScheme.semver2:
SemverV2Strategies.DEVELOPMENT
break;
case VersionScheme.staticMarker:
StaticMarkerStrategies.DEVELOPMENT
break
default:
SemverV1Strategies.DEVELOPMENT
}
}))

preReleaseStrategy.set(versionScheme.map({ scheme ->
scheme == VersionScheme.semver2 ? SemverV2Strategies.PRE_RELEASE : SemverV1Strategies.PRE_RELEASE
switch (scheme) {
case VersionScheme.semver2:
SemverV2Strategies.PRE_RELEASE
break;
case VersionScheme.staticMarker:
StaticMarkerStrategies.PRE_RELEASE
break
default:
SemverV1Strategies.PRE_RELEASE
}
}))

finalStrategy.set(versionScheme.map({ scheme ->
scheme == VersionScheme.semver2 ? SemverV2Strategies.FINAL : SemverV1Strategies.FINAL
switch (scheme) {
case VersionScheme.semver2:
SemverV2Strategies.FINAL
break;
case VersionScheme.staticMarker:
StaticMarkerStrategies.FINAL
break
default:
SemverV1Strategies.FINAL
}
}))

defaultStrategy.set(developmentStrategy)
Expand Down Expand Up @@ -191,6 +272,18 @@ class DefaultVersionPluginExtension implements VersionPluginExtension {
project.properties.get(VersionConsts.LEGACY_VERSION_STAGE_OPTION)
})

releaseBranchPattern.set( project.provider({
(System.getenv()[VersionConsts.RELEASE_BRANCH_PATTERN_ENV_VAR] ?:
project.properties.get(VersionConsts.RELEASE_BRANCH_PATTERN_OPTION) ?:
VersionConsts.DEFAULT_RELEASE_BRANCH_PATTERN).toString()
}))

mainBranchPattern.set(project.provider({
(System.getenv()[VersionConsts.MAIN_BRANCH_PATTERN_ENV_VAR] ?:
project.properties.get(VersionConsts.MAIN_BRANCH_PATTERN_OPTION) ?:
VersionConsts.DEFAULT_MAIN_BRANCH_PATTERN).toString()
}))

version = new MemoisationProvider(project.provider({
def versionStrategies = versionStrategies.get()
def defaultStrategy = defaultStrategy.get()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2018-2020 Wooga GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*/

package wooga.gradle.version.internal.release.base

import com.github.zafarkhaja.semver.ParseException
import com.github.zafarkhaja.semver.Version
import org.ajoberstar.grgit.Tag

class MarkerTagStrategy extends TagStrategy {

private final String prefix

Closure<Version> parseTag = { Tag tag ->
try {
if(tag.name.startsWith(prefix)) {
Version.valueOf(tag.name.replace(prefix,""))
} else
{
null
}

} catch (ParseException e) {
null
}
}

MarkerTagStrategy(String prefix) {
super(false)
this.prefix = prefix
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package wooga.gradle.version.internal.release.opinion

import wooga.gradle.version.internal.release.semver.ChangeScope
import wooga.gradle.version.internal.release.semver.SemVerStrategyState

import static wooga.gradle.version.internal.release.semver.StrategyUtil.*

Expand Down Expand Up @@ -150,13 +152,13 @@ final class Strategies {

if (majorDiff == 1 && minor <= 0) {
// major is off by one and minor is either 0 or not in the branch name
return incrementNormalFromScope(state, wooga.gradle.version.internal.release.semver.ChangeScope.MAJOR)
return incrementNormalFromScope(state, ChangeScope.MAJOR)
} else if (minorDiff == 1 && minor > 0) {
// minor is off by one and specified in the branch name
return incrementNormalFromScope(state, wooga.gradle.version.internal.release.semver.ChangeScope.MINOR)
return incrementNormalFromScope(state, ChangeScope.MINOR)
} else if (majorDiff == 0 && minorDiff == 0 && minor >= 0) {
// major and minor match, both are specified in branch name
return incrementNormalFromScope(state, wooga.gradle.version.internal.release.semver.ChangeScope.PATCH)
return incrementNormalFromScope(state, ChangeScope.PATCH)
} else if (majorDiff == 0 && minor < 0) {
// only major specified in branch name and already matches
return state
Expand All @@ -172,9 +174,18 @@ final class Strategies {
/**
* Always use the scope provided to increment the normal component.
*/
static PartialSemVerStrategy useScope(wooga.gradle.version.internal.release.semver.ChangeScope scope) {
static PartialSemVerStrategy useScope(ChangeScope scope) {
return closure { state -> incrementNormalFromScope(state, scope) }
}

static final PartialSemVerStrategy USE_MARKER_TAG = closure { SemVerStrategyState state ->
def markerVersion = state.nearestCiMarker
if(state.currentBranch.name.matches(state.releaseBranchPattern)) {
markerVersion = state.nearestReleaseMarker
}
state = state.copyWith(inferredNormal: markerVersion.normal)
return state
}
}

/**
Expand Down Expand Up @@ -251,6 +262,17 @@ final class Strategies {
state
}
}

static final PartialSemVerStrategy COUNT_COMMITS_SINCE_MARKER = closure { SemVerStrategyState state ->
def markerVersion = state.nearestCiMarker
if(state.currentBranch.name.matches(state.releaseBranchPattern)) {
markerVersion = state.nearestReleaseMarker
}

def count = markerVersion.distanceFromAny
def inferred = state.inferredPreRelease ? "${state.inferredPreRelease}.${count}" : "${count}"
return state.copyWith(inferredPreRelease: inferred)
}
}

/**
Expand Down Expand Up @@ -280,11 +302,11 @@ final class Strategies {
* If the {@code release.scope} property is set, use it. Or if the nearest any's normal component is different
* than the nearest normal version, use it. Or, if nothing else, use PATCH scope.
*/
static final wooga.gradle.version.internal.release.semver.SemVerStrategy DEFAULT = new wooga.gradle.version.internal.release.semver.SemVerStrategy(
static final SemVerStrategy DEFAULT = new SemVerStrategy(
name: '',
stages: [] as SortedSet,
allowDirtyRepo: false,
normalStrategy: one(Normal.USE_SCOPE_PROP, Normal.USE_NEAREST_ANY, Normal.useScope(wooga.gradle.version.internal.release.semver.ChangeScope.PATCH)),
normalStrategy: one(Normal.USE_SCOPE_PROP, Normal.USE_NEAREST_ANY, Normal.useScope(ChangeScope.PATCH)),
preReleaseStrategy: PreRelease.NONE,
buildMetadataStrategy: BuildMetadata.NONE,
createTag: true,
Expand All @@ -296,7 +318,7 @@ final class Strategies {
* not enforce precedence. The pre-release compoment will always be "SNAPSHOT"
* and no build metadata will be used. Tags will not be created for these versions.
*/
static final wooga.gradle.version.internal.release.semver.SemVerStrategy SNAPSHOT = DEFAULT.copyWith(
static final SemVerStrategy SNAPSHOT = DEFAULT.copyWith(
name: 'snapshot',
stages: ['SNAPSHOT'] as SortedSet,
allowDirtyRepo: true,
Expand All @@ -314,7 +336,7 @@ final class Strategies {
* will note if the repository is dirty. The abbreviated ID of the HEAD will
* be used as build metadata.
*/
static final wooga.gradle.version.internal.release.semver.SemVerStrategy DEVELOPMENT = DEFAULT.copyWith(
static final SemVerStrategy DEVELOPMENT = DEFAULT.copyWith(
name: 'development',
stages: ['dev'] as SortedSet,
allowDirtyRepo: true,
Expand All @@ -331,7 +353,7 @@ final class Strategies {
* note that this strategy uses the same name as {@code PRE_RELEASE_ALPHA_BETA}
* so it cannot be used at the same time.
*/
static final wooga.gradle.version.internal.release.semver.SemVerStrategy PRE_RELEASE = DEFAULT.copyWith(
static final SemVerStrategy PRE_RELEASE = DEFAULT.copyWith(
name: 'pre-release',
stages: ['milestone', 'rc'] as SortedSet,
preReleaseStrategy: all(PreRelease.STAGE_FIXED, PreRelease.COUNT_INCREMENTED)
Expand All @@ -345,7 +367,7 @@ final class Strategies {
* that this strategy uses the same name as {@code PRE_RELEASE} so it cannot be used
* at the same time.
*/
static final wooga.gradle.version.internal.release.semver.SemVerStrategy PRE_RELEASE_ALPHA_BETA = PRE_RELEASE.copyWith(
static final SemVerStrategy PRE_RELEASE_ALPHA_BETA = PRE_RELEASE.copyWith(
name: 'pre-release',
stages: ['alpha', 'beta', 'rc'] as SortedSet
)
Expand All @@ -355,7 +377,7 @@ final class Strategies {
* will enforce precedence. The pre-release and build metadata components
* will always be empty.
*/
static final wooga.gradle.version.internal.release.semver.SemVerStrategy FINAL = DEFAULT.copyWith(
static final SemVerStrategy FINAL = DEFAULT.copyWith(
name: 'final',
stages: ['final'] as SortedSet
)
Expand Down
Loading

0 comments on commit 4b16e67

Please sign in to comment.