diff --git a/docs/configuration.md b/docs/configuration.md index 04ed44ae24..c58116bb93 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -71,6 +71,19 @@ while still updating the `AssemblyVersion` and `AssemblyInformationVersion` attributes. Valid values: `MajorMinorPatchTag`, `MajorMinorPatch`, `MajorMinor`, `Major`, `None`. +### assembly-file-versioning-format +Set this to any of the available [variables](/more-info/variables) in combination (but not necessary) with +a process scoped environment variable. It overwrites the value of `assembly-file-versioning-scheme`. To reference +an environment variable, use `env:` +Example Syntax #1: `'{Major}.{Minor}.{Patch}.{env:JENKINS_BUILD_NUMBER ?? fallback_string}'`. Uses `JENKINS_BUILD_NUMBER` +if available in the environment otherwise the `fallback_string` +Example Syntax #2: `'{Major}.{Minor}.{Patch}.{env:JENKINS_BUILD_NUMBER}'`. Uses `JENKINS_BUILD_NUMBER` +if available in the environment otherwise the parsing fails. +String interpolation is supported as in `assembly-informational-format` + +### assembly-versioning-format +Follows the same semantics as `assembly-file-versioning-format` and overwrites the value of `assembly-versioning-scheme`. + ### assembly-informational-format Set this to any of the available [variables](/more-info/variables) to change the value of the `AssemblyInformationalVersion` attribute. Default set to diff --git a/src/GitVersionCore.Tests/CommitDateTests.cs b/src/GitVersionCore.Tests/CommitDateTests.cs index 4872031fdd..8520786baf 100644 --- a/src/GitVersionCore.Tests/CommitDateTests.cs +++ b/src/GitVersionCore.Tests/CommitDateTests.cs @@ -27,7 +27,7 @@ public void CommitDateFormatTest(string format, string expectedOutcome) }, new EffectiveConfiguration( - AssemblyVersioningScheme.MajorMinorPatch, AssemblyFileVersioningScheme.MajorMinorPatch, "", VersioningMode.ContinuousDelivery, "", "", "", IncrementStrategy.Inherit, + AssemblyVersioningScheme.MajorMinorPatch, AssemblyFileVersioningScheme.MajorMinorPatch, "", "", "", VersioningMode.ContinuousDelivery, "", "", "", IncrementStrategy.Inherit, "", true, "", "", false, "", "", "", "", CommitMessageIncrementMode.Enabled, 4, 4, 4, Enumerable.Empty(), false, true, format) ); diff --git a/src/GitVersionCore.Tests/GitVersionCore.Tests.csproj b/src/GitVersionCore.Tests/GitVersionCore.Tests.csproj index d1f5a93bf4..6c7f1ad723 100644 --- a/src/GitVersionCore.Tests/GitVersionCore.Tests.csproj +++ b/src/GitVersionCore.Tests/GitVersionCore.Tests.csproj @@ -143,6 +143,7 @@ + diff --git a/src/GitVersionCore.Tests/StringFormatWithExtensionTests.cs b/src/GitVersionCore.Tests/StringFormatWithExtensionTests.cs new file mode 100644 index 0000000000..1981e192fb --- /dev/null +++ b/src/GitVersionCore.Tests/StringFormatWithExtensionTests.cs @@ -0,0 +1,129 @@ +using System; + +using GitVersion; +using NUnit.Framework; + +namespace GitVersionCore.Tests +{ + [TestFixture] + + public class StringFormatWithExtensionTests + { + [Test] + public void FormatWith_NoTokens() + { + var propertyObject = new { }; + var target = "Some String without tokens"; + var expected = target; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FormatWith_SingleSimpleToken() + { + var propertyObject = new { SomeProperty = "SomeValue" }; + var target = "{SomeProperty}"; + var expected = "SomeValue"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FormatWith_MultipleTokensAndVerbatimText() + { + var propertyObject = new { SomeProperty = "SomeValue", AnotherProperty = "Other Value" }; + var target = "{SomeProperty} some text {AnotherProperty}"; + var expected = "SomeValue some text Other Value"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FormatWith_EnvVarToken() + { + Environment.SetEnvironmentVariable("GIT_VERSION_TEST_VAR", "Env Var Value"); + var propertyObject = new { }; + var target = "{env:GIT_VERSION_TEST_VAR}"; + var expected = "Env Var Value"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FormatWith_EnvVarTokenWithFallback() + { + Environment.SetEnvironmentVariable("GIT_VERSION_TEST_VAR", "Env Var Value"); + var propertyObject = new { }; + var target = "{env:GIT_VERSION_TEST_VAR ?? fallback}"; + var expected = "Env Var Value"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FormatWith_UnsetEnvVarTokenWithFallback() + { + Environment.SetEnvironmentVariable("GIT_VERSION_UNSET_TEST_VAR", null); + var propertyObject = new { }; + var target = "{env:GIT_VERSION_UNSET_TEST_VAR ?? fallback}"; + var expected = "fallback"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FormatWith_MultipleEnvVars() + { + Environment.SetEnvironmentVariable("GIT_VERSION_TEST_VAR_1", "Val-1"); + Environment.SetEnvironmentVariable("GIT_VERSION_TEST_VAR_2", "Val-2"); + var propertyObject = new { }; + var target = "{env:GIT_VERSION_TEST_VAR_1} and {env:GIT_VERSION_TEST_VAR_2}"; + var expected = "Val-1 and Val-2"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FormatWith_MultipleEnvChars() + { + var propertyObject = new { }; + //Test the greediness of the regex in matching env: char + var target = "{env:env:GIT_VERSION_TEST_VAR_1} and {env:DUMMY_VAR ?? fallback}"; + var expected = "{env:env:GIT_VERSION_TEST_VAR_1} and fallback"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + + [Test] + public void FormatWith_MultipleFallbackChars() + { + var propertyObject = new { }; + //Test the greediness of the regex in matching env: and ?? chars + var target = "{env:env:GIT_VERSION_TEST_VAR_1} and {env:DUMMY_VAR ??? fallback}"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(target, actual); + } + + [Test] + public void FormatWith_SingleFallbackChar() + { + Environment.SetEnvironmentVariable("DUMMY_ENV_VAR", "Dummy-Val"); + var propertyObject = new { }; + //Test the sanity of the regex when there is a grammar mismatch + var target = "{en:DUMMY_ENV_VAR} and {env:DUMMY_ENV_VAR??fallback}"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(target, actual); + } + + [Test] + public void FormatWIth_NullPropagationWithMultipleSpaces() + { + var propertyObject = new { SomeProperty = "Some Value" }; + var target = "{SomeProperty} and {env:DUMMY_ENV_VAR ?? fallback}"; + var expected = "Some Value and fallback"; + var actual = target.FormatWith(propertyObject); + Assert.AreEqual(expected, actual); + } + } +} diff --git a/src/GitVersionCore.Tests/TestEffectiveConfiguration.cs b/src/GitVersionCore.Tests/TestEffectiveConfiguration.cs index 1fc326056a..876de76ac1 100644 --- a/src/GitVersionCore.Tests/TestEffectiveConfiguration.cs +++ b/src/GitVersionCore.Tests/TestEffectiveConfiguration.cs @@ -10,6 +10,8 @@ public class TestEffectiveConfiguration : EffectiveConfiguration public TestEffectiveConfiguration( AssemblyVersioningScheme assemblyVersioningScheme = AssemblyVersioningScheme.MajorMinorPatch, AssemblyFileVersioningScheme assemblyFileVersioningScheme = AssemblyFileVersioningScheme.MajorMinorPatch, + string assemblyVersioningFormat = null, + string assemblyFileVersioningFormat = null, string assemblyInformationalFormat = null, VersioningMode versioningMode = VersioningMode.ContinuousDelivery, string gitTagPrefix = "v", @@ -32,7 +34,7 @@ public TestEffectiveConfiguration( bool tracksReleaseBranches = false, bool isRelease = false, string commitDateFormat = "yyyy-MM-dd") : - base(assemblyVersioningScheme, assemblyFileVersioningScheme, assemblyInformationalFormat, versioningMode, gitTagPrefix, tag, nextVersion, IncrementStrategy.Patch, + base(assemblyVersioningScheme, assemblyFileVersioningScheme, assemblyInformationalFormat, assemblyVersioningFormat, assemblyFileVersioningFormat, versioningMode, gitTagPrefix, tag, nextVersion, IncrementStrategy.Patch, branchPrefixToTrim, preventIncrementForMergedBranchVersion, tagNumberPattern, continuousDeploymentFallbackTag, trackMergeTarget, majorMessage, minorMessage, patchMessage, noBumpMessage, diff --git a/src/GitVersionCore/Configuration/Config.cs b/src/GitVersionCore/Configuration/Config.cs index a1d7e3f010..733b294292 100644 --- a/src/GitVersionCore/Configuration/Config.cs +++ b/src/GitVersionCore/Configuration/Config.cs @@ -26,6 +26,12 @@ public Config() [YamlMember(Alias = "assembly-informational-format")] public string AssemblyInformationalFormat { get; set; } + [YamlMember(Alias = "assembly-versioning-format")] + public string AssemblyVersioningFormat { get; set; } + + [YamlMember(Alias = "assembly-file-versioning-format")] + public string AssemblyFileVersioningFormat { get; set; } + [YamlMember(Alias = "mode")] public VersioningMode? VersioningMode { get; set; } diff --git a/src/GitVersionCore/Configuration/ConfigurationProvider.cs b/src/GitVersionCore/Configuration/ConfigurationProvider.cs index b4fc482c8e..6c78f4b037 100644 --- a/src/GitVersionCore/Configuration/ConfigurationProvider.cs +++ b/src/GitVersionCore/Configuration/ConfigurationProvider.cs @@ -88,6 +88,8 @@ public static void ApplyDefaultsTo(Config config) config.AssemblyVersioningScheme = config.AssemblyVersioningScheme ?? AssemblyVersioningScheme.MajorMinorPatch; config.AssemblyFileVersioningScheme = config.AssemblyFileVersioningScheme ?? AssemblyFileVersioningScheme.MajorMinorPatch; config.AssemblyInformationalFormat = config.AssemblyInformationalFormat; + config.AssemblyVersioningFormat = config.AssemblyVersioningFormat; + config.AssemblyFileVersioningFormat = config.AssemblyFileVersioningFormat; config.TagPrefix = config.TagPrefix ?? DefaultTagPrefix; config.VersioningMode = config.VersioningMode ?? VersioningMode.ContinuousDelivery; config.ContinuousDeploymentFallbackTag = config.ContinuousDeploymentFallbackTag ?? "ci"; diff --git a/src/GitVersionCore/EffectiveConfiguration.cs b/src/GitVersionCore/EffectiveConfiguration.cs index 3ce643e31c..abf2cd9aec 100644 --- a/src/GitVersionCore/EffectiveConfiguration.cs +++ b/src/GitVersionCore/EffectiveConfiguration.cs @@ -12,6 +12,8 @@ public EffectiveConfiguration( AssemblyVersioningScheme assemblyVersioningScheme, AssemblyFileVersioningScheme assemblyFileVersioningScheme, string assemblyInformationalFormat, + string assemblyVersioningFormat, + string assemblyFileVersioningFormat, VersioningMode versioningMode, string gitTagPrefix, string tag, string nextVersion, IncrementStrategy increment, string branchPrefixToTrim, @@ -35,6 +37,8 @@ public EffectiveConfiguration( AssemblyVersioningScheme = assemblyVersioningScheme; AssemblyFileVersioningScheme = assemblyFileVersioningScheme; AssemblyInformationalFormat = assemblyInformationalFormat; + AssemblyVersioningFormat = assemblyVersioningFormat; + AssemblyFileVersioningFormat = assemblyFileVersioningFormat; VersioningMode = versioningMode; GitTagPrefix = gitTagPrefix; Tag = tag; @@ -67,6 +71,8 @@ public EffectiveConfiguration( public AssemblyVersioningScheme AssemblyVersioningScheme { get; private set; } public AssemblyFileVersioningScheme AssemblyFileVersioningScheme { get; private set; } public string AssemblyInformationalFormat { get; private set; } + public string AssemblyVersioningFormat { get; private set; } + public string AssemblyFileVersioningFormat { get; private set; } /// /// Git tag prefix diff --git a/src/GitVersionCore/GitVersionContext.cs b/src/GitVersionCore/GitVersionContext.cs index 67bd267ef0..4478d330b4 100644 --- a/src/GitVersionCore/GitVersionContext.cs +++ b/src/GitVersionCore/GitVersionContext.cs @@ -122,6 +122,8 @@ void CalculateEffectiveConfiguration() var assemblyVersioningScheme = FullConfiguration.AssemblyVersioningScheme.Value; var assemblyFileVersioningScheme = FullConfiguration.AssemblyFileVersioningScheme.Value; var assemblyInformationalFormat = FullConfiguration.AssemblyInformationalFormat; + var assemblyVersioningFormat = FullConfiguration.AssemblyVersioningFormat; + var assemblyFileVersioningFormat = FullConfiguration.AssemblyFileVersioningFormat; var gitTagPrefix = FullConfiguration.TagPrefix; var majorMessage = FullConfiguration.MajorVersionBumpMessage; var minorMessage = FullConfiguration.MinorVersionBumpMessage; @@ -132,7 +134,7 @@ void CalculateEffectiveConfiguration() var commitMessageVersionBump = currentBranchConfig.CommitMessageIncrementing ?? FullConfiguration.CommitMessageIncrementing.Value; Configuration = new EffectiveConfiguration( - assemblyVersioningScheme, assemblyFileVersioningScheme, assemblyInformationalFormat, versioningMode, gitTagPrefix, + assemblyVersioningScheme, assemblyFileVersioningScheme, assemblyInformationalFormat, assemblyVersioningFormat, assemblyFileVersioningFormat, versioningMode, gitTagPrefix, tag, nextVersion, incrementStrategy, currentBranchConfig.Regex, preventIncrementForMergedBranchVersion, diff --git a/src/GitVersionCore/GitVersionCore.csproj b/src/GitVersionCore/GitVersionCore.csproj index acebe812b1..d95644ffd2 100644 --- a/src/GitVersionCore/GitVersionCore.csproj +++ b/src/GitVersionCore/GitVersionCore.csproj @@ -121,6 +121,7 @@ + @@ -232,4 +233,4 @@ - + \ No newline at end of file diff --git a/src/GitVersionCore/Helpers/EnvironmentHelper.cs b/src/GitVersionCore/Helpers/EnvironmentHelper.cs new file mode 100644 index 0000000000..84d35afe0d --- /dev/null +++ b/src/GitVersionCore/Helpers/EnvironmentHelper.cs @@ -0,0 +1,12 @@ +using System; + +namespace GitVersion.Helpers +{ + public class EnvironmentHelper + { + public static string GetEnvironmentVariableForProcess(string envVar) + { + return Environment.GetEnvironmentVariable(envVar, EnvironmentVariableTarget.Process); + } + } +} diff --git a/src/GitVersionCore/OutputVariables/VariableProvider.cs b/src/GitVersionCore/OutputVariables/VariableProvider.cs index ef6acb5c55..5781041b9e 100644 --- a/src/GitVersionCore/OutputVariables/VariableProvider.cs +++ b/src/GitVersionCore/OutputVariables/VariableProvider.cs @@ -43,23 +43,14 @@ public static VersionVariables GetVariablesFor(SemanticVersion semanticVersion, var semverFormatValues = new SemanticVersionFormatValues(semanticVersion, config); - string informationalVersion; + string informationalVersion = CheckAndFormatString(config.AssemblyInformationalFormat, semverFormatValues, + semverFormatValues.DefaultInformationalVersion, "AssemblyInformationalVersion"); - if (string.IsNullOrEmpty(config.AssemblyInformationalFormat)) - { - informationalVersion = semverFormatValues.DefaultInformationalVersion; - } - else - { - try - { - informationalVersion = config.AssemblyInformationalFormat.FormatWith(semverFormatValues); - } - catch (ArgumentException formex) - { - throw new WarningException(string.Format("Unable to format AssemblyInformationalVersion. Check your format string: {0}", formex.Message)); - } - } + string assemblyFileSemVer = CheckAndFormatString(config.AssemblyFileVersioningFormat, semverFormatValues, + semverFormatValues.AssemblyFileSemVer, "AssemblyFileVersioningFormat"); + + string assemblySemVer = CheckAndFormatString(config.AssemblyVersioningFormat, semverFormatValues, + semverFormatValues.AssemblySemVer, "AssemblyVersioningFormat"); var variables = new VersionVariables( semverFormatValues.Major, @@ -75,8 +66,8 @@ public static VersionVariables GetVariablesFor(SemanticVersion semanticVersion, semverFormatValues.LegacySemVer, semverFormatValues.LegacySemVerPadded, semverFormatValues.FullSemVer, - semverFormatValues.AssemblySemVer, - semverFormatValues.AssemblyFileSemVer, + assemblySemVer, + assemblyFileSemVer, semverFormatValues.PreReleaseTag, semverFormatValues.PreReleaseTagWithDash, semverFormatValues.PreReleaseLabel, @@ -100,5 +91,28 @@ static void PromoteNumberOfCommitsToTagNumber(SemanticVersion semanticVersion) semanticVersion.BuildMetaData.CommitsSinceVersionSource = semanticVersion.BuildMetaData.CommitsSinceTag ?? 0; semanticVersion.BuildMetaData.CommitsSinceTag = null; } + + static string CheckAndFormatString(string formatString, T source, string defaultValue, string formatVarName) + { + string formattedString; + + if (string.IsNullOrEmpty(formatString)) + { + formattedString = defaultValue; + } + else + { + try + { + formattedString = formatString.FormatWith(source); + } + catch (ArgumentException formex) + { + throw new WarningException(string.Format("Unable to format {0}. Check your format string: {1}", formatVarName, formex.Message)); + } + } + + return formattedString; + } } } \ No newline at end of file diff --git a/src/GitVersionCore/StringFormatWith.cs b/src/GitVersionCore/StringFormatWith.cs index a33c1ded82..693eb5b814 100644 --- a/src/GitVersionCore/StringFormatWith.cs +++ b/src/GitVersionCore/StringFormatWith.cs @@ -8,7 +8,7 @@ namespace GitVersion static class StringFormatWithExtension { - private static readonly Regex TokensRegex = new Regex(@"{\w+}", RegexOptions.Compiled); + private static readonly Regex TokensRegex = new Regex(@"{(?env:)??\w+(\s+(\?\?)??\s+\w+)??}", RegexOptions.Compiled); /// /// Formats a string template with the given source object. @@ -30,13 +30,40 @@ public static string FormatWith(this string template, T source) foreach (Match match in TokensRegex.Matches(template)) { var memberAccessExpression = TrimBraces(match.Value); - Func expression = CompileDataBinder(objType, memberAccessExpression); - string propertyValue = expression(source); + string propertyValue = null; + + // Support evaluation of environment variables in the format string + // For example: {env:JENKINS_BUILD_NUMBER ?? fall-back-string} + + if (match.Groups["env"].Success) + { + memberAccessExpression = memberAccessExpression.Substring(memberAccessExpression.IndexOf(':') + 1); + string envVar = memberAccessExpression, fallback = null; + string[] components = (memberAccessExpression.Contains("??")) ? memberAccessExpression.Split(new string[] { "??" }, StringSplitOptions.None) : null; + if (components != null) + { + envVar = components[0].Trim(); + fallback = components[1].Trim(); + } + + propertyValue = Helpers.EnvironmentHelper.GetEnvironmentVariableForProcess(envVar); + if (propertyValue == null) + { + if (fallback != null) + propertyValue = fallback; + else + throw new ArgumentException(string.Format("Environment variable {0} not found and no fallback string provided", envVar)); + } + } + else + { + Func expression = CompileDataBinder(objType, memberAccessExpression); + propertyValue = expression(source); + } template = template.Replace(match.Value, propertyValue); } return template; - } @@ -73,6 +100,5 @@ static Func CompileDataBinder(Type type, string expr) return Expression.Lambda>(body, param).Compile(); } - } } \ No newline at end of file