3

I want to verify that the version being used when packing some nuget-packages using dotnet build /p:VERSION=1.2.3 and GeneratePackageOnBuild. My regex expressen is working in LINQPad 6 using C#:

Regex.Match("1.2.3", @"^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$")

However in my default.props that is being imported by all csproj-files (which are using the new sdk-style, if that is relevant) I have this and it is not working at all:

<Target Name="ValidateVersion" BeforeTargets="BeforeBuild">
  <PropertyGroup>
    <VersionRegex>^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$</VersionRegex>
    <VersionTest>1.2.3</VersionTest> <!-- Just to make it easier during testing -->
  </PropertyGroup>

  <Error
    Text="Version is not following the correct format: $(VersionRegex)"
    Condition=" $([System.Text.RegularExpressions.Regex]::IsMatch('$(VersionTest)', `$(VersionRegex)`)) " />
</Target>

It does not matter if I inline VersionRegex and VersionTest, it is still not working. Any ideas why it is working in C# but not in MSBuild?

Oskar
  • 1,996
  • 1
  • 22
  • 39
  • I got nothing on this System (only here because of the C# tag), but usually types have to be properly anotated. And those do not look like they are notated properly as string. How ho the text and condition strings below are anotated. – Christopher Nov 28 '19 at 19:46
  • 1
    could be that it's not coming across as expected with xml escaping. try sticking your regex inside a CDATA. – vhoang Nov 28 '19 at 19:49
  • @viethoang: there are only 5 characters that need to be escaped/encoded in XML: `<`, `>`, `&` and both single-quote (/apostrophe) and double-quote. I don't see any of those – Flydog57 Nov 28 '19 at 20:21
  • True, next thought is to replace the four single quotes inside IsMatch() with " – vhoang Nov 29 '19 at 01:39
  • @Christopher Sounds plausible. How do I annotate them as strings? I tried to inline the variable as `[System.String]'^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$'` and with back ticks but I still get the same result. – Oskar Nov 29 '19 at 08:08
  • @Oskar You anotate them the same way you did with those other strings below: `Text="Version is not following the correct format: $(VersionRegex)"` One point of regex is that it is a matching rule, stored in a plain old string. As such it should be as close to "universally communicateable" as possible. – Christopher Nov 29 '19 at 14:05

2 Answers2

3

Workaround

I haven't found the actual issue but a workaround is, as @Viet Hoang mentioned in the comments, to use CDATA:

Targets/ValidateVersioning.targets:

<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <UsingTask
    TaskName="ValidateVersion"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
    <ParameterGroup>
      <Version ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Using Namespace="System"/>
      <Using Namespace="System.IO"/>
      <Using Namespace="System.Text.RegularExpressions"/>
      <Code Type="Fragment" Language="cs">
<![CDATA[
if (!Regex.Match(Version, @"^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$").Success)
{
    Log.LogError("Version has wrong format: {0}", Version);
    return false;
}
]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

default.props:

<Project>

...

  <Import Project="Targets\ValidateVersioning.targets" />
  <Target Condition="$(VERSION) != ''" Name="ValidateVersion" BeforeTargets="BeforeBuild">
    <ValidateVersion Version="$(VERSION)" />
  </Target>

...

</Project>

> dotnet build --no-restore -p:Version=1.3.4 will work but

> dotnet build --no-restore -p:Version=1.3 will not build

Oskar
  • 1,996
  • 1
  • 22
  • 39
3

From your original example, you should be able to put the content of the VersionRegex property within CDATA:

<Target Name="ValidateVersion" BeforeTargets="BeforeBuild">
  <PropertyGroup>
    <VersionRegex><![CDATA[^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$]]></VersionRegex>
    <VersionTest>1.2.3</VersionTest>
  </PropertyGroup>

  <Error
    Text="Version is not following the correct format: $(VersionRegex)"
    Condition="!$([System.Text.RegularExpressions.Regex]::IsMatch('$(VersionTest)', '$(VersionRegex)'))" />
</Target>
br3nt
  • 9,017
  • 3
  • 42
  • 63
  • Thanks, it seems to be working! Can you add a `!` to the beginning of `Condition`? I will mark your answer as accepted after that. – Oskar Feb 06 '20 at 06:48
  • 1
    Funnily enough, I'll likely be using your answer as I'm trying to use named match groups, but MSBuild wont let me access `$([System.Text.RegularExpressions.Regex]::Match($(VersionTest), $(VersionRegex)).Groups["my_group"]` – br3nt Feb 06 '20 at 06:54
  • Great that my answer still can be useful to others! – Oskar Feb 06 '20 at 06:55