From cc8c34112acc0e870e624ec0255bd8df760898e0 Mon Sep 17 00:00:00 2001
From: Joaquim Alvino de Mesquita Neto
+ * For example, if the nearest any is {@code 1.2.3-alpha.1} and the
+ * nearest normal is {@code 1.2.2}, this will infer the normal
+ * component as {@code 1.2.3}.
+ *
+ *
+ */
+ static PartialSemVerStrategy fromMatchingBranchName(String branchName, Pattern pattern) {
+ return closure { SemVerStrategyState state ->
+ def m = branchName =~ pattern
if (m) {
def major = m.groupCount() >= 1 ? parseIntOrZero(m[0][1]) : -1
def minor = m.groupCount() >= 2 ? parseIntOrZero(m[0][2]) : -1
-
def normal = state.nearestVersion.normal
def majorDiff = major - normal.majorVersion
def minorDiff = minor - normal.minorVersion
@@ -167,7 +211,7 @@ final class Strategies {
// only major specified in branch name and already matches
return state
} else {
- throw new GradleException("Invalid branch (${state.currentBranch.name}) for nearest normal (${normal}).")
+ throw new GradleException("Invalid branch (${branchName}) for nearest normal (${state.nearestVersion.normal}).", e)
}
} else {
return state
@@ -175,6 +219,21 @@ final class Strategies {
}
}
+ /**
+ * Uses given scope if state's branch name matches pattern
+ * @param pattern - Pattern to match with state's branch name
+ * @param scope - Scope to be used in strategy if pattern matches
+ * @return PartialSemVerStrategy that executes the operation described above
+ */
+ static PartialSemVerStrategy scopeIfBranchMatchesPattern(Pattern pattern, ChangeScope scope) {
+ return closure { SemVerStrategyState state ->
+ def m = state.currentBranch.name =~ pattern
+ if (m.matches()) {
+ return useScope(scope).infer(state)
+ }
+ return state
+ }
+ }
/**
* Always use the scope provided to increment the normal component.
*/
@@ -207,10 +266,14 @@ final class Strategies {
static final PartialSemVerStrategy STAGE_FIXED = closure { state -> state.copyWith(inferredPreRelease: state.stageFromProp) }
/**
- * Sets the pre-release component to the value of {@link SemVerStrategyState#stageFromProp}.
+ * Appends a timestamp in the format yyyyMMddHHmm to the pre-release component
+ * @param separator - join component between the pre-release component and the timestamp.
+ * @return partial strategy function appendint timestamp to the pre-release component.
*/
- static final PartialSemVerStrategy STAGE_TIMESTAMP = closure { state ->
- state.copyWith(inferredPreRelease: "${GenerateTimestamp()}")
+ static PartialSemVerStrategy withTimestamp(String separator = ".") {
+ closure { SemVerStrategyState state ->
+ state.copyWith(inferredPreRelease: "${state.inferredPreRelease}${separator}${GenerateTimestamp()}")
+ }
}
/**
@@ -243,28 +306,74 @@ final class Strategies {
}
}
+ /**
+ * Appends a branch name to the pre-release component.
+ * @param separator - string used to join prerelease and branch strings defaults to Dot(.)
+ * @param branchTransform - potential transformations to branch name, defaults to identity
+ * @return
+ */
+ static PartialSemVerStrategy withBranchName(String separator = ".",
+ Closure
+ * This strategy infers the release version by checking the nearest any release. + * If a {@code pre-release} with the same {@code major}.{@code minor}.{@code patch} version exists, bumps the count part. + *
+ * Example new pre release: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.2.0" + * nearestAnyVersion = "" + * inferred = "1.3.0-rc00001" + * } + *+ *
+ * Example pre release version exists: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.2.0" + * nearestAnyVersion = "1.3.0-rc00001" + * inferred = "1.3.0-rc00002" + * } + *+ *
+ * Example last final release higher than pre-release: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * nearestAnyVersion = "1.3.0-rc00001" + * inferred = "1.4.0-rc00001" + * } + *+ */ + static final SemVerStrategy PRE_RELEASE = Strategies.PRE_RELEASE.copyWith( + normalStrategy: NORMAL_STRATEGY, + preReleaseStrategy: all ( + Strategies.PreRelease.STAGE_FIXED, + Strategies.PreRelease.countIncremented("", 5), + ) + ) + + /** + * Returns a version strategy to be used for {@code final} builds. + *
+ * This strategy infers the release version by checking the nearest release. + *
+ * Example: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * inferred = "1.4.0" + * } + *+ */ + static final SemVerStrategy FINAL = Strategies.FINAL.copyWith(normalStrategy: NORMAL_STRATEGY) + + /** + * Returns a version strategy to be used for {@code development} builds. + *
+ * This strategy creates a unique version string based on last commit hash and the + * distance of commits to nearest normal version. + * This version string is not compatible with Paket or + * Nuget + *
+ * Example: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * commitHash = "90c90b9" + * distance = 22 + * inferred = "1.3.0-dev.22+90c90b9" + * } + *+ */ + static final SemVerStrategy DEVELOPMENT = Strategies.DEVELOPMENT.copyWith( + normalStrategy: NORMAL_STRATEGY, + buildMetadataStrategy: Strategies.BuildMetadata.COMMIT_ABBREVIATED_ID + ) + + /** + * Returns a version strategy to be used for {@code snapshot} builds. + *
+ * This strategy creates a snapshot version suitable for Paket and + * Nuget. {@code Nuget} and {@code Paket} don't support + * {@code SNAPSHOT} versions or any numerical values after the {@code patch} component. We trick these package managers + * by creating a unique version based on {@code branch} and the distance of commits to nearest normal version. + * If the branch name contains numerical values, they will be converted into alphanumerical counterparts. + * The {@code master} branch is a special case so it will end up being higher than any other branch build (m>b) + *
+ * Example from master branch: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * branch = "master" + * distance = 22 + * inferred = "1.4.0-master00022" + * } + *+ *
+ * Example from topic branch: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * branch = "feature/fix_22" + * distance = 34 + * inferred = "1.4.0-branchFeatureFixTwoTwo00034" + * } + *+ */ + static final SemVerStrategy SNAPSHOT = Strategies.PRE_RELEASE.copyWith( + name: 'snapshot', + stages: ['snapshot','SNAPSHOT'] as SortedSet, + normalStrategy: NORMAL_STRATEGY, + preReleaseStrategy: all(Strategies.PreRelease.PAKET_BRANCH_NAME, + Strategies.PreRelease.countCommitsSinceNormal("", 5)), + createTag: false, + allowDirtyRepo: true, + enforcePrecedence: false, + releaseStage: ReleaseStage.Snapshot + ) +} diff --git a/src/main/groovy/wooga/gradle/version/strategies/NewSemverV2Strategies.groovy b/src/main/groovy/wooga/gradle/version/strategies/NewSemverV2Strategies.groovy new file mode 100644 index 0000000..a88d53f --- /dev/null +++ b/src/main/groovy/wooga/gradle/version/strategies/NewSemverV2Strategies.groovy @@ -0,0 +1,161 @@ +/* + * Copyright 2017 the original author or authors. + * + * 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.strategies + +import wooga.gradle.version.ReleaseStage +import wooga.gradle.version.internal.release.opinion.Strategies +import wooga.gradle.version.internal.release.semver.SemVerStrategy +import wooga.gradle.version.strategies.partials.NormalPartials + +import static wooga.gradle.version.internal.release.semver.StrategyUtil.* + + +final class NewSemverV2Strategies { + + static final NORMAL_STRATEGY = one( + Strategies.Normal.USE_SCOPE_STATE, + NormalPartials.SCOPE_FROM_BRANCH, + Strategies.Normal.USE_NEAREST_ANY + ) + + /** + * Returns a version strategy to be used for {@code final} builds. + *
+ * This strategy infers the release version by checking the nearest release. + *
+ * Example: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * inferred = "1.4.0" + * } + *+ */ + static final SemVerStrategy FINAL = Strategies.FINAL.copyWith( + name: 'production', + allowDirtyRepo: true, + normalStrategy: NORMAL_STRATEGY, + stages: ['final','production'] as SortedSet, + releaseStage: ReleaseStage.Final + ) + /** + * Returns a version strategy to be used for {@code pre-release}/{@code candidate} builds. + *
+ * This strategy infers the release version by checking the nearest any release. + * If a {@code pre-release} with the same {@code major}.{@code minor}.{@code patch} version exists, bumps the count part. + *
+ * Example new pre release: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.2.0" + * nearestAnyVersion = "" + * inferred = "1.3.0-rc.1" + * } + *+ *
+ * Example pre release version exists: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.2.0" + * nearestAnyVersion = "1.3.0-rc.1" + * inferred = "1.3.0-rc.2" + * } + *+ *
+ * Example last final release higher than pre-release: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * nearestAnyVersion = "1.3.0-rc.1" + * inferred = "1.4.0-rc.1" + * } + *+ */ + static final SemVerStrategy PRE_RELEASE = Strategies.PRE_RELEASE.copyWith( + name: 'pre-release', + normalStrategy: NORMAL_STRATEGY, + stages: ['rc', 'staging'] as SortedSet, + preReleaseStrategy: all(Strategies.PreRelease.STAGE_FIXED, Strategies.PreRelease.COUNT_INCREMENTED), + releaseStage: ReleaseStage.Prerelease, + allowDirtyRepo: true, + ) + + /** + * Returns a version strategy to be used for {@code development} builds. + *
+ * This strategy creates a unique version string based on last commit hash and the + * distance of commits to nearest normal version. + * This version string is not compatible with Paket or + * Nuget + *
+ * Example: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * commitHash = "90c90b9" + * distance = 22 + * inferred = "1.3.0-dev.22+90c90b9" + * } + *+ */ + static final SemVerStrategy DEVELOPMENT = Strategies.DEVELOPMENT.copyWith( + normalStrategy: NORMAL_STRATEGY, + buildMetadataStrategy: Strategies.BuildMetadata.COMMIT_ABBREVIATED_ID, + ) + + /** + * Returns a version strategy to be used for {@code snapshot} builds. + *
+ * This strategy creates a snapshot version based on Semver 2.0.0. + * Branch names will be encoded in the pre-release part of the version. + *
+ * Example from master branch: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * branch = "master" + * distance = 22 + * inferred = "1.4.0-master.22" + * } + *+ *
+ * Example from topic branch: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * branch = "feature/fix_22" + * distance = 34 + * inferred = "1.4.0-branch.feature.fix.22.34" + * } + *+ */ + static final SemVerStrategy SNAPSHOT = Strategies.SNAPSHOT.copyWith( + stages: ['ci', 'snapshot', 'SNAPSHOT'] as SortedSet, + normalStrategy: NORMAL_STRATEGY, + allowDirtyRepo: true, + preReleaseStrategy: all(Strategies.PreRelease.WITH_BRANCH_NAME, + Strategies.PreRelease.COUNT_COMMITS_SINCE_ANY), + ) +} diff --git a/src/main/groovy/wooga/gradle/version/strategies/SemverV1Strategies.groovy b/src/main/groovy/wooga/gradle/version/strategies/SemverV1Strategies.groovy index 89016c6..05d5651 100644 --- a/src/main/groovy/wooga/gradle/version/strategies/SemverV1Strategies.groovy +++ b/src/main/groovy/wooga/gradle/version/strategies/SemverV1Strategies.groovy @@ -28,15 +28,20 @@ import wooga.gradle.version.internal.release.semver.StrategyUtil import static wooga.gradle.version.internal.release.semver.StrategyUtil.closure import static wooga.gradle.version.internal.release.semver.StrategyUtil.parseIntOrZero +/** + * Please use LegacyNuGetStrategies instead + */ +@Deprecated class SemverV1Strategies { static final scopes = StrategyUtil.one( - Strategies.Normal.USE_SCOPE_PROP, + Strategies.Normal.USE_SCOPE_STATE, Strategies.Normal.ENFORCE_GITFLOW_BRANCH_MAJOR_X, Strategies.Normal.ENFORCE_BRANCH_MAJOR_X, Strategies.Normal.ENFORCE_GITFLOW_BRANCH_MAJOR_MINOR_X, Strategies.Normal.ENFORCE_BRANCH_MAJOR_MINOR_X, Strategies.Normal.USE_NEAREST_ANY, - Strategies.Normal.useScope(ChangeScope.PATCH)) + Strategies.Normal.useScope(ChangeScope.PATCH) + ) static final PartialSemVerStrategy COUNT_INCREMENTED = closure { SemVerStrategyState state -> def nearest = state.nearestVersion diff --git a/src/main/groovy/wooga/gradle/version/strategies/SemverV2Strategies.groovy b/src/main/groovy/wooga/gradle/version/strategies/SemverV2Strategies.groovy index b3580b0..de52119 100644 --- a/src/main/groovy/wooga/gradle/version/strategies/SemverV2Strategies.groovy +++ b/src/main/groovy/wooga/gradle/version/strategies/SemverV2Strategies.groovy @@ -29,10 +29,14 @@ import java.util.regex.Pattern import static wooga.gradle.version.internal.release.semver.StrategyUtil.* +/** + * Deprecated, please use SemverV2WithDefaultStrategies instead. + */ +@Deprecated final class SemverV2Strategies { private static final scopes = one( - Strategies.Normal.USE_SCOPE_PROP, + Strategies.Normal.USE_SCOPE_STATE, Normal.matchBranchPatternAndUseScope(~/feature(?:\/|-).+$/, ChangeScope.MINOR), Normal.matchBranchPatternAndUseScope(~/hotfix(?:\/|-).+$/, ChangeScope.PATCH), Normal.matchBranchPatternAndUseScope(~/fix(?:\/|-).+$/, ChangeScope.MINOR), diff --git a/src/main/groovy/wooga/gradle/version/strategies/StaticMarkerStrategies.groovy b/src/main/groovy/wooga/gradle/version/strategies/StaticMarkerStrategies.groovy index 913b8f7..87df13e 100644 --- a/src/main/groovy/wooga/gradle/version/strategies/StaticMarkerStrategies.groovy +++ b/src/main/groovy/wooga/gradle/version/strategies/StaticMarkerStrategies.groovy @@ -122,7 +122,7 @@ class StaticMarkerStrategies { */ static final SemVerStrategy DEVELOPMENT = Strategies.DEVELOPMENT.copyWith( normalStrategy: scopes, - buildMetadataStrategy: NetflixOssStrategies.BuildMetadata.DEVELOPMENT_METADATA_STRATEGY) + buildMetadataStrategy: Strategies.BuildMetadata.COMMIT_ABBREVIATED_ID) /** * Returns a version strategy to be used for {@code snapshot} builds. @@ -156,7 +156,8 @@ class StaticMarkerStrategies { name: 'snapshot', stages: ['ci'] as SortedSet, createTag: false, - preReleaseStrategy: all(SemverV2Strategies.PreRelease.STAGE_BRANCH_NAME, Strategies.PreRelease.COUNT_COMMITS_SINCE_MARKER), + preReleaseStrategy: all(Strategies.PreRelease.WITH_BRANCH_NAME, + Strategies.PreRelease.COUNT_COMMITS_SINCE_MARKER), enforcePrecedence: false ) diff --git a/src/main/groovy/wooga/gradle/version/strategies/WdkStrategies.groovy b/src/main/groovy/wooga/gradle/version/strategies/WdkStrategies.groovy index eb002b9..5ae98af 100644 --- a/src/main/groovy/wooga/gradle/version/strategies/WdkStrategies.groovy +++ b/src/main/groovy/wooga/gradle/version/strategies/WdkStrategies.groovy @@ -1,23 +1,10 @@ package wooga.gradle.version.strategies -import wooga.gradle.version.ReleaseStage -import wooga.gradle.version.internal.release.opinion.Strategies -import wooga.gradle.version.internal.release.semver.SemVerStrategy -import wooga.gradle.version.internal.release.semver.StrategyUtil +import wooga.gradle.version.strategies.opinion.WdkNuGetStrategies -class WdkStrategies { - static final SemVerStrategy DEVELOPMENT = SemverV1Strategies.DEVELOPMENT - static final SemVerStrategy SNAPSHOT = SemverV1Strategies.SNAPSHOT - static final SemVerStrategy PREFLIGHT = SemverV1Strategies.SNAPSHOT.copyWith( - releaseStage: ReleaseStage.Preflight, - // TODO: Must start Between m-r - stages: ['pre', 'preflight'] as SortedSet, - preReleaseStrategy: StrategyUtil.all(StrategyUtil.closure({ state -> - def stage = Strategies.PreRelease.STAGE_FIXED.infer(state).inferredPreRelease - def integration = Strategies.PreRelease.STAGE_TIMESTAMP.infer(state).inferredPreRelease - state.copyWith(inferredPreRelease: "$stage$integration") - })), - ) - static final SemVerStrategy PRE_RELEASE = SemverV1Strategies.PRE_RELEASE - static final SemVerStrategy FINAL = SemverV1Strategies.FINAL +/** + * Deprecated: please use WdkNuGetStrategies instead + */ +@Deprecated +class WdkStrategies extends WdkNuGetStrategies { } diff --git a/src/main/groovy/wooga/gradle/version/strategies/operations/NormalPartials.groovy b/src/main/groovy/wooga/gradle/version/strategies/operations/NormalPartials.groovy new file mode 100644 index 0000000..9411513 --- /dev/null +++ b/src/main/groovy/wooga/gradle/version/strategies/operations/NormalPartials.groovy @@ -0,0 +1,81 @@ +package wooga.gradle.version.strategies.operations + +import org.gradle.api.Project +import wooga.gradle.version.internal.release.opinion.Strategies +import wooga.gradle.version.internal.release.semver.ChangeScope +import wooga.gradle.version.internal.release.semver.PartialSemVerStrategy +import wooga.gradle.version.internal.release.semver.SemVerStrategyState +import wooga.gradle.version.strategies.NetflixOssStrategies + +import java.util.regex.Pattern + +import static wooga.gradle.version.internal.release.semver.StrategyUtil.closure +import static wooga.gradle.version.internal.release.semver.StrategyUtil.one + +class NormalPartials { + + static final SCOPE_GITFLOW_BRANCH_TYPE = one( + scopeForBranchPattern(~/hotfix(?:\/|-).+$/, ChangeScope.PATCH), + scopeForBranchPattern(~/feature(?:\/|-).+$/, ChangeScope.MINOR), + scopeForBranchPattern(~/fix(?:\/|-).+$/, ChangeScope.MINOR), + ) + + static final SCOPE_EMBED_IN_BRANCH = one( + Strategies.Normal.ENFORCE_GITFLOW_BRANCH_MAJOR_X, + Strategies.Normal.ENFORCE_GITFLOW_BRANCH_MAJOR_MINOR_X, + Strategies.Normal.ENFORCE_BRANCH_MAJOR_X, + Strategies.Normal.ENFORCE_BRANCH_MAJOR_MINOR_X, + ) + + static final SCOPE_FROM_BRANCH = one( + SCOPE_GITFLOW_BRANCH_TYPE, + SCOPE_EMBED_IN_BRANCH + ) + + @Deprecated + static final PartialSemVerStrategy TRAVIS_BRANCH_MAJOR_X = fromBranchProperty(~/^(\d+)\.x$/) + @Deprecated + static final PartialSemVerStrategy TRAVIS_BRANCH_MAJOR_MINOR_X = fromBranchProperty(~/^(\d+)\.(\d+)\.x$/) + + /** + * If the nearest any is higher from the nearest normal, sets the + * normal component to the nearest any's normal component. Otherwise + * do nothing. + * + *
+ * For example, if the nearest any is {@code 1.2.3-alpha.1} and the + * nearest normal is {@code 1.2.2}, this will infer the normal + * component as {@code 1.2.3}. + *
+ */ + static final PartialSemVerStrategy NEAREST_HIGHER_ANY = closure { state -> + def nearest = state.nearestVersion + if (nearest.any.lessThanOrEqualTo(nearest.normal)) { + return state + } else { + return state.copyWith(inferredNormal: nearest.any.normalVersion) + } + } + + static PartialSemVerStrategy scopeForBranchPattern(Pattern pattern, ChangeScope scope) { + return closure { SemVerStrategyState state -> + def m = state.currentBranch.name =~ pattern + if (m.matches()) { + return Strategies.Normal.useScope(scope).infer(state) + } + return state + } + } + + static PartialSemVerStrategy fromBranchProperty(Project project = NetflixOssStrategies.project, + String branchProperty = NetflixOssStrategies.TRAVIS_BRANCH_PROP, + Pattern pattern) { + return closure { SemVerStrategyState state -> + if (project.hasProperty(branchProperty)) { + def branch = project.property(branchProperty).toString() + return Strategies.Normal.fromMatchingBranchName(branch, pattern).infer(state) + } + return state + } + } +} diff --git a/src/main/groovy/wooga/gradle/version/strategies/opinion/LegacyNuGetStrategies.groovy b/src/main/groovy/wooga/gradle/version/strategies/opinion/LegacyNuGetStrategies.groovy new file mode 100644 index 0000000..f03c44e --- /dev/null +++ b/src/main/groovy/wooga/gradle/version/strategies/opinion/LegacyNuGetStrategies.groovy @@ -0,0 +1,50 @@ +package wooga.gradle.version.strategies.opinion + + +import wooga.gradle.version.internal.release.opinion.Strategies +import wooga.gradle.version.internal.release.semver.ChangeScope +import wooga.gradle.version.internal.release.semver.PartialSemVerStrategy +import wooga.gradle.version.internal.release.semver.SemVerStrategy +import wooga.gradle.version.internal.release.semver.StrategyUtil +import wooga.gradle.version.strategies.NewSemverV1Strategies + +/** + * NuGet/Paket compatible strategies. Uses NewSemverV1Strategies as basis, + * plus using PATCH as a fallback if no change scope is provided. + */ +class LegacyNuGetStrategies { + + /** + * Scope that will be set when no scope is provided to the strategies under this class + */ + static final ChangeScope DEFAULT_SCOPE = ChangeScope.PATCH + + /** + * Similar to NewSemverV1Strategies.DEVELOPMENT, but its scope defaults to DEFAULT_SCOPE when no scope is provide + */ + static final SemVerStrategy DEVELOPMENT = NewSemverV1Strategies.DEVELOPMENT.copyWith( + normalStrategy: chainDefaultScope(NewSemverV1Strategies.DEVELOPMENT) + ) + /** + * Similar to NewSemverV1Strategies.SNAPSHOT, but its scope defaults to DEFAULT_SCOPE when no scope is provide + */ + static final SemVerStrategy SNAPSHOT = NewSemverV1Strategies.SNAPSHOT.copyWith( + normalStrategy: chainDefaultScope(NewSemverV1Strategies.SNAPSHOT) + ) + /** + * Similar to NewSemverV1Strategies.PRE_RELEASE, but its scope defaults to DEFAULT_SCOPE when no scope is provide + */ + static final SemVerStrategy PRE_RELEASE = NewSemverV1Strategies.PRE_RELEASE.copyWith( + normalStrategy: chainDefaultScope(NewSemverV1Strategies.PRE_RELEASE) + ) + /** + * Similar to NewSemverV1Strategies.FINAL, but its scope defaults to DEFAULT_SCOPE when no scope is provide + */ + static final SemVerStrategy FINAL = NewSemverV1Strategies.FINAL.copyWith( + normalStrategy: chainDefaultScope(NewSemverV1Strategies.FINAL) + ) + + private static PartialSemVerStrategy chainDefaultScope(SemVerStrategy base, ChangeScope scope = DEFAULT_SCOPE) { + return StrategyUtil.one(base.normalStrategy, Strategies.Normal.useScope(scope)) + } +} diff --git a/src/main/groovy/wooga/gradle/version/strategies/opinion/SemverV2WithDefaultStrategies.groovy b/src/main/groovy/wooga/gradle/version/strategies/opinion/SemverV2WithDefaultStrategies.groovy new file mode 100644 index 0000000..6a4ff72 --- /dev/null +++ b/src/main/groovy/wooga/gradle/version/strategies/opinion/SemverV2WithDefaultStrategies.groovy @@ -0,0 +1,131 @@ +package wooga.gradle.version.strategies.opinion + +import wooga.gradle.version.internal.release.opinion.Strategies +import wooga.gradle.version.internal.release.semver.ChangeScope +import wooga.gradle.version.internal.release.semver.PartialSemVerStrategy +import wooga.gradle.version.internal.release.semver.SemVerStrategy +import wooga.gradle.version.internal.release.semver.StrategyUtil +import wooga.gradle.version.strategies.NewSemverV2Strategies + +/** + * SemverV2 strategies that uses MINOR as a fallback in case a change scope is not provided. + */ +class SemverV2WithDefaultStrategies { + + /** + * Returns a version strategy to be used for {@code final} builds. + *+ * This strategy infers the release version by checking the nearest release. + *
+ * Example: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * inferred = "1.4.0" + * } + *+ */ + static final SemVerStrategy FINAL = NewSemverV2Strategies.FINAL.copyWith( + normalStrategy: chainDefaultScope(NewSemverV2Strategies.FINAL) + ) + /** + * Returns a version strategy to be used for {@code pre-release}/{@code candidate} builds. + *
+ * This strategy infers the release version by checking the nearest any release. + * If a {@code pre-release} with the same {@code major}.{@code minor}.{@code patch} version exists, bumps the count part. + *
+ * Example new pre release: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.2.0" + * nearestAnyVersion = "" + * inferred = "1.3.0-rc.1" + * } + *+ *
+ * Example pre release version exists: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.2.0" + * nearestAnyVersion = "1.3.0-rc.1" + * inferred = "1.3.0-rc.2" + * } + *+ *
+ * Example last final release higher than pre-release: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * nearestAnyVersion = "1.3.0-rc.1" + * inferred = "1.4.0-rc.1" + * } + *+ */ + static final SemVerStrategy PRE_RELEASE = NewSemverV2Strategies.PRE_RELEASE.copyWith( + normalStrategy: chainDefaultScope(NewSemverV2Strategies.PRE_RELEASE) + ) + + /** + * Returns a version strategy to be used for {@code development} builds. + *
+ * This strategy creates a unique version string based on last commit hash and the + * distance of commits to nearest normal version. + * This version string is not compatible with Paket or + * Nuget + *
+ * Example: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * commitHash = "90c90b9" + * distance = 22 + * inferred = "1.3.0-dev.22+90c90b9" + * } + *+ */ + static final SemVerStrategy DEVELOPMENT = NewSemverV2Strategies.DEVELOPMENT.copyWith( + normalStrategy: chainDefaultScope(NewSemverV2Strategies.DEVELOPMENT), + ) + + /** + * Returns a version strategy to be used for {@code snapshot} builds. + *
+ * This strategy creates a snapshot version based on Semver 2.0.0. + * Branch names will be encoded in the pre-release part of the version. + *
+ * Example from master branch: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * branch = "master" + * distance = 22 + * inferred = "1.4.0-master.22" + * } + *+ *
+ * Example from topic branch: + *
+ * {@code + * releaseScope = "minor" + * nearestVersion = "1.3.0" + * branch = "feature/fix_22" + * distance = 34 + * inferred = "1.4.0-branch.feature.fix.22.34" + * } + *+ */ + static final SemVerStrategy SNAPSHOT = NewSemverV2Strategies.SNAPSHOT.copyWith( + normalStrategy: chainDefaultScope(NewSemverV2Strategies.SNAPSHOT), + ) + + private static PartialSemVerStrategy chainDefaultScope(SemVerStrategy base, ChangeScope scope = ChangeScope.MINOR) { + return StrategyUtil.one(base.normalStrategy, Strategies.Normal.useScope(scope)) + } + +} diff --git a/src/main/groovy/wooga/gradle/version/strategies/opinion/WdkNuGetStrategies.groovy b/src/main/groovy/wooga/gradle/version/strategies/opinion/WdkNuGetStrategies.groovy new file mode 100644 index 0000000..dbd2be0 --- /dev/null +++ b/src/main/groovy/wooga/gradle/version/strategies/opinion/WdkNuGetStrategies.groovy @@ -0,0 +1,52 @@ +package wooga.gradle.version.strategies.opinion + +import wooga.gradle.version.ReleaseStage +import wooga.gradle.version.internal.release.opinion.Strategies +import wooga.gradle.version.internal.release.semver.SemVerStrategy + +import static wooga.gradle.version.internal.release.semver.StrategyUtil.all + +/** + * WDK strategies for NuGet/Paket. Based on LegacyNuGetStrategies, plus an extra PREFLIGHT stage. + */ +class WdkNuGetStrategies { + /** + * Same as LegacyNuGetStrategies.DEVELOPMENT + */ + static final SemVerStrategy DEVELOPMENT = LegacyNuGetStrategies.DEVELOPMENT + /** + * Same as LegacyNuGetStrategies.SNAPSHOT + */ + static final SemVerStrategy SNAPSHOT = LegacyNuGetStrategies.SNAPSHOT + /** + * Returns a version strategy to be used for {@code preflight} builds. + *
+ * This strategy creates a wdk-specific preflight version based on Semver 1.0. + * The pre-release part of the version consists of the stage name(pre or preflight) and a timestamp (yyyyMMddHHmm), with no separation. + * There are no metadata part in the generated versions. + *
+ * Example: +
+ {@code + stage = "pre" + releaseScope = "minor" + nearestVersion = "1.3.0" + current date = 01/01/2022 10:10:30 + inferred = "1.4.0-pre202201011010" + } + */ + static final SemVerStrategy PREFLIGHT = LegacyNuGetStrategies.SNAPSHOT.copyWith( + releaseStage: ReleaseStage.Preflight, + // TODO: Must start Between m-r + stages: ['pre', 'preflight'] as SortedSet, + preReleaseStrategy: all(Strategies.PreRelease.STAGE_FIXED, Strategies.PreRelease.withTimestamp("")) + ) + /** + * Same as LegacyNuGetStrategies.PRE_RELEASE + */ + static final SemVerStrategy PRE_RELEASE = LegacyNuGetStrategies.PRE_RELEASE + /** + * Same as LegacyNuGetStrategies.FINAL + */ + static final SemVerStrategy FINAL = LegacyNuGetStrategies.FINAL +} diff --git a/src/main/groovy/wooga/gradle/version/strategies/partials/NormalPartials.groovy b/src/main/groovy/wooga/gradle/version/strategies/partials/NormalPartials.groovy new file mode 100644 index 0000000..5b61302 --- /dev/null +++ b/src/main/groovy/wooga/gradle/version/strategies/partials/NormalPartials.groovy @@ -0,0 +1,27 @@ +package wooga.gradle.version.strategies.partials + + +import wooga.gradle.version.internal.release.opinion.Strategies +import wooga.gradle.version.internal.release.semver.ChangeScope +import static wooga.gradle.version.internal.release.semver.StrategyUtil.one + +class NormalPartials { + + static final SCOPE_GITFLOW_BRANCH_TYPE = one( + Strategies.Normal.scopeIfBranchMatchesPattern(~/hotfix(?:\/|-).+$/, ChangeScope.PATCH), + Strategies.Normal.scopeIfBranchMatchesPattern(~/feature(?:\/|-).+$/, ChangeScope.MINOR), + Strategies.Normal.scopeIfBranchMatchesPattern(~/fix(?:\/|-).+$/, ChangeScope.MINOR), + ) + + static final SCOPE_EMBED_IN_BRANCH = one( + Strategies.Normal.ENFORCE_GITFLOW_BRANCH_MAJOR_X, + Strategies.Normal.ENFORCE_GITFLOW_BRANCH_MAJOR_MINOR_X, + Strategies.Normal.ENFORCE_BRANCH_MAJOR_X, + Strategies.Normal.ENFORCE_BRANCH_MAJOR_MINOR_X, + ) + + static final SCOPE_FROM_BRANCH = one( + SCOPE_GITFLOW_BRANCH_TYPE, + SCOPE_EMBED_IN_BRANCH + ) +} diff --git a/src/test/groovy/wooga/gradle/version/VersionPluginSpec.groovy b/src/test/groovy/wooga/gradle/version/VersionPluginSpec.groovy index e1d1034..0ace3f0 100644 --- a/src/test/groovy/wooga/gradle/version/VersionPluginSpec.groovy +++ b/src/test/groovy/wooga/gradle/version/VersionPluginSpec.groovy @@ -39,7 +39,6 @@ class VersionPluginSpec extends ProjectSpec { git = Grgit.init(dir: projectDir) git.add(patterns: ['.gitignore']) git.commit(message: 'initial commit') -// git.tag.add(name: 'v0.0.1') } @Ignore @@ -972,7 +971,7 @@ class VersionPluginSpec extends ProjectSpec { } - if(nearestNormal != _) { + if (nearestNormal != _) { 5.times { git.commit(message: 'feature commit') }