GitInfo icon indicating copy to clipboard operation
GitInfo copied to clipboard

Branch name always set to HEAD in Gitlab build

Open demconsido opened this issue 1 year ago • 1 comments

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"

Back this issue Back this issue

demconsido avatar Oct 17 '24 07:10 demconsido

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 🙏

kzu avatar Oct 22 '24 19:10 kzu

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.

demconsido avatar Oct 29 '24 11:10 demconsido

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.

kzu avatar Oct 29 '24 17:10 kzu

The package that does this for you, is ThisAssembly.Git.

Which, I'd say is the natural successor to this package.

kzu avatar Oct 29 '24 17:10 kzu