Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Populate new csproj format properties from Azure DevOps build pipeline task #1611

Open
roryprimrose opened this issue Mar 1, 2019 · 9 comments

Comments

@roryprimrose
Copy link

commented Mar 1, 2019

The existing build tasks for Azure DevOps have long had the option to update AssemblyInfo.cs before running a build task (which is really sweet BTW). Is there going to be support in the future for updating the version/package metadata properties in the new csproj format from the build task?

I've previously used a powershell script to take the output of the GitVersion variables to manually go into all the csproj files and update the properties before running dotnet build. It would be great if a future version of the build task could do this OOTB.

I'll try to find the powershell script I use which may better explain what I'm trying to achieve.

@roryprimrose

This comment has been minimized.

Copy link
Author

commented Mar 1, 2019

This is the powershell script I am using between running the GitVersion build task and the dotnet build task.

$buildVersion = $env:GitVersion_NuGetVersionV2 
$sourcesDirectory = $env:BUILD_SOURCESDIRECTORY

Write-Host "Setting version $buildVersion. Searching for projects"

# Find all the csproj files
if ($buildVersion -eq $null) {
    Write-Error ("GitVersion_NuGetVersionV2 environment variable is missing.")
    exit 1
}

if ($sourcesDirectory -eq $null) {
    Write-Error ("BUILD_SOURCESDIRECTORY environment variable is missing.")
    exit 1
}

# This code snippet gets all the files in $Path that end in ".csproj" and any subdirectories.
Get-ChildItem -Path $sourcesDirectory -Filter "*.csproj" -Recurse -File | 
    ForEach-Object { 
        $projectPath = $_.FullName
        $project = Select-Xml $projectPath -XPath "//Project"
        
        $version = $project.Node.SelectSingleNode("PropertyGroup/Version")

        if ($version -eq $null) {
            Write-Host "Adding Version element to $projectPath"

            $group = $project.Node.SelectSingleNode("PropertyGroup")
            $version = $group.OwnerDocument.CreateElement("Version")
            $group.AppendChild($version) | Out-Null
        }

        $version.InnerText = $env:GitVersion_NuGetVersionV2
        $version.OwnerDocument.Save($projectPath)

        Write-Host "Saved version $($env:GitVersion_NuGetVersionV2) to $projectPath"
    }
@arturcic

This comment has been minimized.

Copy link
Member

commented Mar 1, 2019

You could also create/update the Directory.Build.props file with the properties you're interested in.

That would be a good addition to the Build Task, for example create Directory.Build.props for new sdk based projects and keep AssemblyInfo.cs for older project types.

You can have a look how we use it in GitVersion
https://github.com/GitTools/GitVersion/blob/master/src/Directory.Build.props

@roryprimrose

This comment has been minimized.

Copy link
Author

commented Mar 5, 2019

I haven't used props files before so I've been reading up on this file and I think I get how this might work. For example, this file could be created/updated to have something like the following (I'm totally guessing here).

<PropertyGroup>
    <AssemblyVersion>$(GitVersion_AssemblySemVer)</AssemblyVersion>
    <FileVersion>$(GitVersion_MajorMinorPatch)</FileVersion>
    <InformationalVersion>$(GitVersion_InformationalVersion )</InformationalVersion>
</PropertyGroup>

In order to use Directory.Build.props for this purpose I can think of the following scenarios that would need to be handled:

  • No Directory.Build.props file exists under source control
    • Create the file with the above properties
    • Probably easy
  • A single Directory.Build.props exists somewhere and does not contain the required properties
    • Add the above properties to the existing file
    • Kinda easy, probably...
  • A single Directory.Build.props exists somewhere and does contain the required properties
    • Add missing properties
    • Who wins on the conflicting properties?
    • This starts to suck
  • Multiple existing Directory.Build.props files exist in any folder between the project and solution root

If you can safely figure out how to handle existing Directory.Build.props files then this may work on Azure DevOps because creating/updating a Directory.Build.props file on the build agent repo wouldn't matter as the change would be cleared out after the build. This wouldn't work for the nuget package on a project because a create or update to a Directory.Build.props file would create a change on the file under source control on the developers machine.

Have I totally missed the mark here?

@arturcic

This comment has been minimized.

Copy link
Member

commented Mar 5, 2019

That's a good description of the the possible scenarios.

As far as I understand, the AssemblyInfo can still be used for setting the version number for the sdk style projects.

You can also pass them as build parameters similar to
dotnet build -p:Version=$(GitVersion_AssemblySemVer) (not tested) reference

@roryprimrose

This comment has been minimized.

Copy link
Author

commented Mar 5, 2019

Yep, you could push those three properties into the build task. That does require a manual configuration of the build step though. The thing I like about the AssemblyInfo option on the existing build task (at least for full framework msbuild builds) is that it is a zero config effort on the build workflow.

@roryprimrose

This comment has been minimized.

Copy link
Author

commented Mar 6, 2019

I've been thinking about this a bit more. The PowerShell script above is really just doing a similar action to what the AssemblyInfo logic does in the existing build task. It would be easier in the case of the new proj format though because it is xml rather than parsing the AssemblyInfo text file.

This process still wouldn't work for the GitVersionTask NuGet package because it would change what is under source control.

FYI, I've updated my script to include the other properties.

$nuGetVersion = $env:GitVersion_NuGetVersionV2
$sourcesDirectory = $env:BUILD_SOURCESDIRECTORY

Write-Host "Searching for projects under $($sourcesDirectory)"

# Find all the csproj files
if ($nuGetVersion -eq $null) {
    Write-Error ("GitVersion_NuGetVersionV2 environment variable is missing.")
    exit 1
}

if ($env:GitVersion_AssemblySemVer -eq $null) {
    Write-Error ("GitVersion_AssemblySemVer environment variable is missing.")
    exit 1
}

if ($env:GitVersion_MajorMinorPatch -eq $null) {
    Write-Error ("GitVersion_MajorMinorPatch environment variable is missing.")
    exit 1
}

if ($env:GitVersion_InformationalVersion -eq $null) {
    Write-Error ("GitVersion_InformationalVersion environment variable is missing.")
    exit 1
}

if ($sourcesDirectory -eq $null) {
    Write-Error ("BUILD_SOURCESDIRECTORY environment variable is missing.")
    exit 1
}

Function Set-NodeValue($rootNode, [string]$nodeName, [string]$value)
{   
    $nodePath = "PropertyGroup/$($nodeName)"
    
    $node = $rootNode.Node.SelectSingleNode($nodePath)

    if ($node -eq $null) {
        Write-Host "Adding $($nodeName) element to existing PropertyGroup"

        $group = $rootNode.Node.SelectSingleNode("PropertyGroup")
        $node = $group.OwnerDocument.CreateElement($nodeName)
        $group.AppendChild($node) | Out-Null
    }

    $node.InnerText = $value

    Write-Host "Set $($nodeName) to $($value)"
}

# This code snippet gets all the files in $Path that end in ".csproj" and any subdirectories.
Get-ChildItem -Path $sourcesDirectory -Filter "*.csproj" -Recurse -File | 
    ForEach-Object { 
        
        Write-Host "Found project at $($_.FullName)"

        $projectPath = $_.FullName
        $project = Select-Xml $projectPath -XPath "//Project"
        
        Set-NodeValue $project "Version" $nuGetVersion
        Set-NodeValue $project "AssemblyVersion" $env:GitVersion_AssemblySemVer
        Set-NodeValue $project "FileVersion" $env:GitVersion_MajorMinorPatch
        Set-NodeValue $project "InformationalVersion" $env:GitVersion_InformationalVersion 

        $document = $project.Node.OwnerDocument
        $document.PreserveWhitespace = $true

        $document.Save($projectPath)

        Write-Host ""
    }

Write-Host "##vso[build.updatebuildnumber]$($nuGetVersion)"

This works fine as a custom DevOps build task but it would be nice if GitVersion did this OOTB :)

@stale

This comment has been minimized.

Copy link

commented Jun 29, 2019

This issue has been automatically marked as stale because it has not had recent activity. After 30 days from now, it will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jun 29, 2019

@roryprimrose

This comment has been minimized.

Copy link
Author

commented Jun 30, 2019

I still think this should be addressed

@stale stale bot removed the stale label Jun 30, 2019

@garfbradaz

This comment has been minimized.

Copy link

commented Aug 13, 2019

Having GitVersion update the .csproj files automatically would be sweet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.