Branch name always set to HEAD in Gitlab build
Bug description
When building locally, branch name is correctly filled in. But building on a Gitlab runner, the branch name is always HEAD. This has to do with Gitlab always checking out specific commit and not full branch, which makes sense.
My current workaround is to add following snippet to my .csproj, after including GitInfo, which basically overrides the generated GitBranch property when on CI:
<PropertyGroup Condition="'$(CI)' != ''">
<GitBranch>$(CI_COMMIT_BRANCH)</GitBranch>
</PropertyGroup>
In GitInfo src/Directory.Build.targets I see:
<PropertyGroup Condition="'$(RepositoryBranch)' == ''">
<!-- ... -->
<!-- GitLab: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html -->
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_TAG)' != ''">$(CI_COMMIT_TAG)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_MERGE_REQUEST_IID)' != ''">pr$(CI_MERGE_REQUEST_IID)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_EXTERNAL_PULL_REQUEST_IID)' != ''">pr$(CI_EXTERNAL_PULL_REQUEST_IID)</RepositoryBranch>
<RepositoryBranch Condition="'$(RepositoryBranch)' == '' and '$(CI_COMMIT_BRANCH)' != ''">$(CI_COMMIT_BRANCH)</RepositoryBranch>
<!-- ... -->
</PropertyGroup>
So this snipped should (ultimately) set the 'RepositoryBranch' to Gitlab variable CI_COMMIT_BRANCH. So is this a bug, or am I doing anything wrong?
Steps to Reproduce
Create or use an existing dotnet project and create a branch 'mybranch' in the git repo and use following project configuration.
Current .csproj (or Build.props) snippet:
<PropertyGroup>
<!-- we'll do our own versioning -->
<GitVersion>false</GitVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsNotAsErrors>8002</WarningsNotAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GitInfo" Version="3.3.4" PrivateAssets="All" />
</ItemGroup>
<!--Override default Version info here with GitInfo values-->
<Target Name="PopulateGitInfo" DependsOnTargets="GitVersion"
BeforeTargets="GetAssemblyVersion;GenerateNuspec;GetPackageContents">
<PropertyGroup>
<Version>$(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch)$(GitSemVerDashLabel)</Version>
<PackageVersion>$(Version)</PackageVersion>
<RepositoryBranch>$(GitBranch)</RepositoryBranch>
<RepositoryCommit>$(GitCommit)</RepositoryCommit>
<SourceRevisionId Condition="'$(GitBranch)' == '' or '$(GitBranch)' == 'HEAD'">0</SourceRevisionId>
<SourceRevisionId Condition="'$(GitBranch)' != '' and '$(GitBranch)' != 'HEAD' and '$(GitIsDirty)' != '1'">$(GitBranch)+$(GitCommit)</SourceRevisionId>
<SourceRevisionId Condition="'$(GitBranch)' != '' and '$(GitBranch)' != 'HEAD' and '$(GitIsDirty)' == '1'">$(GitBranch)+$(GitCommit)M</SourceRevisionId>
</PropertyGroup>
</Target>
<!--Display version info during build-->
<Target Name="TestMessage" AfterTargets="Build">
<Message
Text="Version detected: $(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch)$(GitSemVerDashLabel)-$(GitBranch)+$(GitCommit)" Importance="high" />
<Message Text="Product Version: $(Version).$(SourceRevisionId)" Importance="high" />
</Target>
gitlab-ci.yml:
default:
image:
name: mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022
tags:
- windows
- docker
stages:
- build
build:
stage: build
script:
- dotnet restore
- dotnet build -c Release --no-restore
artifacts:
paths:
- 'src/*/bin/'
- 'src/*/obj/'
- 'test/*/bin/'
expire_in: 1 day
Then push to Gitlab.
Expected Behavior
Gitlab runner should display Version detected and Product Version during build, which should be something like 0.0.1-mybranch+03d5aff
and not:
0.0.1-HEAD+03d5aff
Version Info
GitInfo Version="3.3.4"
Could you try building locally and setting the CI envvars to arbitrary values locally until you can reproduce the issue locally? See https://docs.gitlab.com/ee/ci/variables/predefined_variables.html.
Also, a binlog from that repro would be super helpful to determine what actually is being set and where during the build. Just dun dotnet build -bl and attach the resulting .binlog 🙏
I created a new clean project to only emphasize on the GitInfo issue. It gives the same result.
Directory.Build.props in root folder:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<SignAssembly>False</SignAssembly>
<ImplicitUsings>enable</ImplicitUsings>
<Authors>Yournamehere</Authors>
<Copyright>
TODO: Add specific Copyright notice here
</Copyright>
</PropertyGroup>
<!-- To be redefined by GitInfo after restore. -->
<Target Name="GitVersion" />
<ItemGroup>
<InternalsVisibleTo Include="$(AssemblyName).Tests.Unit" />
<InternalsVisibleTo Include="$(AssemblyName).Tests.Integration" />
<InternalsVisibleTo Include="$(AssemblyName).Tests.System" />
<InternalsVisibleTo Include="$(AssemblyName).Tests.TestApplication" />
</ItemGroup>
</Project>
Directory.Build.props in src subfolder:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Directory.Build.props" />
<PropertyGroup>
<!-- we'll do our own versioning -->
<GitVersion>false</GitVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsNotAsErrors>8002</WarningsNotAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GitInfo" Version="3.3.4" PrivateAssets="All" />
</ItemGroup>
<!--Override default Version info here with GitInfo values. Note that the GitInfo source code is already generated here-->
<Target Name="PopulateGitInfo" DependsOnTargets="GitVersion"
BeforeTargets="GetAssemblyVersion;GenerateNuspec;GetPackageContents">
<PropertyGroup>
<Version>$(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch)$(GitSemVerDashLabel)</Version>
<PackageVersion>$(Version)</PackageVersion>
<RepositoryBranch Condition="'$(GitBranch)' == '$(GitBranchPostfix)' or '$(GitBranch)' == 'HEAD$(GitBranchPostfix)'"></RepositoryBranch>
<RepositoryBranch Condition="'$(GitBranch)' != '$(GitBranchPostfix)' and '$(GitBranch)' != 'HEAD$(GitBranchPostfix)'">$(GitBranch)"</RepositoryBranch>
<RepositoryCommit>$(GitCommit)</RepositoryCommit>
<SourceRevisionId Condition="'$(GitBranch)' == '$(GitBranchPostfix)' or '$(GitBranch)' == 'HEAD$(GitBranchPostfix)'">0</SourceRevisionId>
<SourceRevisionId Condition="'$(GitBranch)' != '$(GitBranchPostfix)' and '$(GitBranch)' != 'HEAD$(GitBranchPostfix)' and '$(GitIsDirty)' != '1'">$(GitBranch).$(GitCommit)</SourceRevisionId>
<SourceRevisionId Condition="'$(GitBranch)' != '$(GitBranchPostfix)' and '$(GitBranch)' != 'HEAD$(GitBranchPostfix)' and '$(GitIsDirty)' == '1'">$(GitBranch).$(GitCommit)M</SourceRevisionId>
</PropertyGroup>
</Target>
</Project>
Actual .csproj in subfolder in src folder:
Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<!--Display version info during build-->
<Target Name="TestMessage" AfterTargets="Build">
<!--Create a property with the constructed version info-->
<PropertyGroup>
<VersionInfoProp Condition="('$(GitBranch)' == '$(GitBranchPostfix)' or '$(GitBranch)' == 'HEAD$(GitBranchPostfix)') and '$(GitIsDirty)' != '1'">$(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch)$(GitSemVerDashLabel)</VersionInfoProp>
<VersionInfoProp Condition="('$(GitBranch)' == '$(GitBranchPostfix)' or '$(GitBranch)' == 'HEAD$(GitBranchPostfix)') and '$(GitIsDirty)' == '1'">$(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch)$(GitSemVerDashLabel)M</VersionInfoProp>
<VersionInfoProp Condition="'$(GitBranch)' != '$(GitBranchPostfix)' and '$(GitBranch)' != 'HEAD$(GitBranchPostfix)' and '$(GitIsDirty)' != '1'">$(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch)$(GitSemVerDashLabel)+$(GitBranch).$(GitCommit)</VersionInfoProp>
<VersionInfoProp Condition="'$(GitBranch)' != '$(GitBranchPostfix)' and '$(GitBranch)' != 'HEAD$(GitBranchPostfix)' and '$(GitIsDirty)' == '1'">$(GitSemVerMajor).$(GitSemVerMinor).$(GitSemVerPatch)$(GitSemVerDashLabel)+$(GitBranch).$(GitCommit)M</VersionInfoProp>
</PropertyGroup>
<!--Display the version info in the build -->
<Message Text="CI: $(CI)" Importance="high" />
<Message Text="CI Branch: $(CI_COMMIT_BRANCH)" Importance="high" />
<Message Text="Branch: $(GitBranch)" Importance="high" />
<Message Text="Version: $(VersionInfoProp)" Importance="high" />
<Message Text="Product Version: $(Version).$(SourceRevisionId)" Importance="high" />
<Message Text="RepositoryBranch: $(RepositoryBranch)" Importance="high" />
<!--Create an intermediate ItemGroup for writing Version Info to file -->
<ItemGroup>
<CiVersionInfo Include="$(VersionInfoProp)" />
</ItemGroup>
<WriteLinesToFile File="$(OutputPath)\version.txt" Lines="@(CiVersionInfo)" Overwrite="true" Encoding="Unicode" />
</Target>
... removed irrelevant part...
</Project>
Output local build:
CI:
CI Branch:
Branch: master
Version: 0.0.1+master.d9a6c68
Product Version: 0.0.1.master.d9a6c68
RepositoryBranch: master
Output local checkout specific commit:
CI:
CI Branch:
Branch: HEAD
Version: 0.0.1
Product Version: 0.0.1.0
RepositoryBranch:
Set environment variables locally to simulate Gitlab environment and build with buildlog:
set CI=true
set CI_COMMIT_BRANCH=master
set CI_COMMIT_TAG=master
dotnet build -bl
Ouput with these manually set environment variables:
CI: true
CI Branch: master
Branch: HEAD
Version: 0.0.1
Product Version: 0.0.1.0
RepositoryBranch:
Ouput Gitlab build:
CI: true
CI Branch: master
Branch: HEAD
Version: 0.0.1
Product Version: 0.0.1.0
RepositoryBranch:
Note: the latter two indeed produce the same result.
Note2: above code contains multiple references to $(GitBranchPostfix), but in this example project it always evaluates to empty string.
Note3: github does not allow me to attach the resulting .binlog. I will mail it to you.
GitInfo does not populate RepositoryBranch. What you are seeing is MY way of defaulting it when I build GitInfo (and that's a generic targets file I use across all my OSS projects).
The GitInfo way is strictly through git commands: https://github.com/devlooped/GitInfo/blob/main/src/GitInfo/build/GitInfo.targets#L405-L435
My approach to defaulting RepositoryBranch is sprinkled in a few PRs here and there, see https://github.com/search?q=repositorybranch%20author%3Akzu&type=issues.
Personally, I think this should be done by dotnet/sourcelink since that's the one providing source control info nowadays.
The package that does this for you, is ThisAssembly.Git.
Which, I'd say is the natural successor to this package.
