Skip to content

Conversation

@jonpryor
Copy link
Contributor

@jonpryor jonpryor commented Feb 10, 2022

Context: 2d5431f
Context: 88d6093
Context: #936
Context: https://github.com/jonpryor/java.interop/commits/jonp-registration-scope

Versioning is hard.

Way back in 3e6a623 we tried to use the GitInfo NuGet package so
that all assemblies would have a version number which contained the
number of commits since GitInfo.txt changed.

This turned out to have unanticipated breakage, and was largely
reverted in 2d5431f for "core" libs like Java.Interop.dll, but
retained for "utility" apps and libs like generator.exe.

This still presents a problem, though: the point to assembly
versioning is to prevent accidental breaking of referencing
assemblies. If we add a new member to Java.Interop.dll but
fail to update the version, then that permits a scenario in which
an app/lib depends on the new member, but is built against a version
missing that member. This results in runtime exceptions.

The whole reason this hasn't been a problem so far is because
Java.Interop.dll has barely changed in years. (Plus, most usage
is hidden behind other layers and libs…)

However, I want this to change: #936 and
jonpryor/java.interop/jonp-registration-scope both add new public
API to Java.Interop.dll, and there are other features and
optimizations we're considering that would also require API changes.
A policy of "no changes" isn't tenable.

Thus: allow Java.Interop.dll built for .NET 6 to have a different
$(Version) than the one built for .NET Standard 2.0.

Fixing this was unexpectedly problematic, as commit 88d6093:

Update[d] Java.Interop.BootstrapTasks.csproj to no longer
<Import/> VersionInfo.targets, as this causes a circular
dependency (VersionInfo.targets uses tasks from
Java.Interop.BootstrapTasks.dll). This is fine, as
Java.Interop.BootstrapTasks.dll doesn't need to be versioned.

Java.Interop.BootstrapTasks.dll doesn't need to be versioned, but
other assemblies do, and this change change meant that
VersionInfo.targets was never used, which in turn meant that e.g.
bin/BuildDebug/Version.props was never created.

This change also implicitly reverted all remaining 3e6a623
behavior; in commit 13def0e (one prior to 88d6093), generator.exe
had a version of 0.1.45.0. Starting with commit 88d6093,
generator.exe had version 1.0.0.0, which re-introduces the
"baseline" scenario which first necessitated 3e6a623!

Re-think this process, while avoiding the circular dependency:

  1. Java.Interop.BootstrapTasks.targets now generates a
    Version.props file, re-introducing its existence.
    Version.props now contains four version values:

    • $(JINetToolVersion): Version to use for "utility"
      assemblies which target .NET.

    • $(JINetCoreLibVersion): Version to use for "core library"
      assemblies which target .NET.

    • $(JIOldToolVersion): Version to use for "utility"
      assemblies which target .NET Standard/Framework/etc.

    • $(JIOldCoreLibVersion): Version to use for "core library"
      assemblies which target .NET Standard/Framework/etc.

    The $(JINet*) values derive their major, minor, and patch
    values from GitInfo, while the $(JIOld*) values are
    backward compatible (-ish).

  2. Update/replace VersionInfo.targets with a
    _SetInformationalVersion target, which sets the
    $(InformationalVersion) MSBuild property based on the value
    of $(Version) and various other properties.

  3. Directory.Build.props is updated to provide new
    $(JIUtilityVersion) and $(JICoreLibVersion) properties, which
    are set based on the $(TargetFramework) value.

  4. Set the default $(Version) value to $(JIUtilityVersion).
    "Core library" assemblies must explicitly set $(Version) in
    their .csproj to instead be $(JICoreLibVersion).

The result is that for "core libraries" such as Java.Interop.dll,
when building for .NET Standard or MonoAndroid they will continue to
use version 0.1.0.0 (see also 2d5431f), while these assemblies will
use version 6.0.0.0 when built for .NET Core/6.

"Utility" assemblies such as generator.exe will contain a version
number which changes based on when GitInfo.txt was last changed.
When building for .NET Standard, they will use version
0.2.$(GitBaseVersionPatch).$(GitCommits), which differs from the
pre-88d6093c pattern of 0.1.$(GitSemVerPatch).0, but as my current
system Xamarin.Android v12.1.99.117 install shows that generator.exe
has version 0.1.31.0, "rebasing" on 0.2.x feels easiest.
When utility assemblies are built for .NET, they will instead use the
values from GitInfo.txt, e.g. 6.0.0.$(GitCommits).

Finally, always set $(FileVersion) to:

$(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch).$(GitCommits)

$(FileVersion) is used to set
$(AssemblyFileVersionAttribute), which is not used for
assembly binding, but is shown in the Windows File Properties
dialog, and can be used to (indirectly) determine which commit an
assembly was built from.

Context: 2d5431f
Context: 88d6093
Context: dotnet#936
Context: https://github.com/jonpryor/java.interop/commits/jonp-registration-scope

Versioning is hard.

Way back in 3e6a623 we tried to use the `GitInfo` NuGet package so
that *all* assemblies would have a version number which contained the
number of commits since `GitInfo.txt` changed.

This turned out to have unanticipated breakage, and was largely
reverted in 2d5431f for "core" libs like `Java.Interop.dll`, but
retained for "utility" apps and libs like `generator.exe`.

This still presents a problem, though: the *point* to assembly
versioning is to prevent accidental breaking of referencing
assemblies.  If we add a new member to `Java.Interop.dll` but
*fail to update the version*, then that *permits* a scenario in which
an app/lib depends on the new member, but is built against a version
missing that member.  This results in runtime exceptions.

The whole reason this hasn't been a problem so far is because
`Java.Interop.dll` has barely changed in *years*.  (Plus, most usage
is hidden behind other layers and libs…)

However, *I want this to change*: dotnet#936 and
jonpryor/java.interop/jonp-registration-scope both *add* new public
API to `Java.Interop.dll`, and there are other features and
optimizations we're considering that would also require API changes.
A policy of "no changes" isn't tenable.

Thus: allow `Java.Interop.dll` built for .NET 6 to have a different
`$(Version)` than the one built for .NET Standard 2.0.

Fixing this was unexpectedly problematic, as commit 88d6093:

>  Update[d] `Java.Interop.BootstrapTasks.csproj` to *no longer*
> `<Import/>` `VersionInfo.targets`, as this causes a circular
> dependency (`VersionInfo.targets` uses tasks from
> `Java.Interop.BootstrapTasks.dll`).  This is fine, as
> `Java.Interop.BootstrapTasks.dll` doesn't need to be versioned.

`Java.Interop.BootstrapTasks.dll` doesn't need to be versioned, but
*other assemblies **do***, and this change change meant that
`VersionInfo.targets` was *never* used, which in turn meant that e.g.
`bin/BuildDebug/Version.props` was never created.

This change *also* implicitly reverted all remaining 3e6a623
behavior; in commit 13def0e (one prior to 88d6093), `generator.exe`
*had* a version of 0.1.45.0.  Starting with commit 88d6093,
`generator.exe` had version 1.0.0.0, which re-introduces the
"baseline" scenario which first necessitated 3e6a623!

Re-think this process, while avoiding the circular dependency:

 1. `Java.Interop.BootstrapTasks.targets` now *generates* a
    `Version.props` file, re-introducing its existence.
    `Version.props` now contains *four* version values:

      * `$(JINetToolVersion)`: Version to use for "utility"
        assemblies which target .NET.

      * `$(JINetCoreLibVersion)`: Version to use for "core library"
        assemblies which target .NET.

      * `$(JIOldToolVersion)`: Version to use for "utility"
        assemblies which target .NET Standard/Framework/etc.

      * `$(JIOldCoreLibVersion)`: Version to use for "core library"
        assemblies which target .NET Standard/Framework/etc.

    The `$(JINet*)` values derive their major, minor, and patch
    values from `GitInfo`, while the `$(JIOld*)` values are
    backward compatible (-ish).

 2. Update/replace `VersionInfo.targets` with a
    `_SetInformationalVersion` target, which sets the
    `$(InformationalVersion)` MSBuild property based on the value
    of `$(Version)` and various other properties.

 3. `Directory.Build.props` is updated to provide new
    `$(JIUtilityVersion)` and `$(JICoreLibVersion)` properties, which
    are set based on the `$(TargetFramework)` value.

 4. Set the default `$(Version)` value to `$(JIUtilityVersion)`.
    "Core library" assemblies must explicitly set `$(Version)` in
    their `.csproj` to instead be `$(JICoreLibVersion)`.

The result is that for "core libraries" such as `Java.Interop.dll`,
when building for .NET Standard or MonoAndroid they will continue to
use version 0.1.0.0 (see also 2d5431f), while these assemblies will
use version 6.0.0.0 when built for .NET Core/6.

"Utility" assemblies such as `generator.exe` will contain a version
number which changes based on when `GitInfo.txt` was last changed.
When building for .NET Standard, they will use version
`0.2.$(GitBaseVersionPatch).$(GitCommits)`, which differs from the
pre-88d6093c pattern of `0.1.$(GitSemVerPatch).0`, but as my current
system Xamarin.Android v12.1.99.117 install shows that `generator.exe`
has version 0.1.31.0, "rebasing" on 0.2.x feels easiest.
When utility assemblies are built for .NET, they will instead use the
values from `GitInfo.txt`, e.g. `6.0.0.$(GitCommits)`.

Finally, *always* set `$(FileVersion)` to:

	$(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch).$(GitCommits)

[`$(FileVersion)`][0] is used to set
[`$(AssemblyFileVersionAttribute)`][1], which is *not* used for
assembly binding, but *is* shown in the Windows File Properties
dialog, and can be used to (indirectly) determine which commit an
assembly was built from.

[0]: https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props
[1]: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assemblyfileversionattribute?view=net-6.0
@jonpryor jonpryor force-pushed the jonp-net6-versioning-v2 branch from ab0c90c to 8d741f3 Compare February 10, 2022 23:54
@jonpryor jonpryor requested a review from jpobst February 11, 2022 00:25
@jonpryor jonpryor merged commit cbd9666 into dotnet:main Feb 11, 2022
@github-actions github-actions bot locked and limited conversation to collaborators Apr 13, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants