How do I auto increment the package version number

2020-06-12 12:30发布

I realize that the build/revision number of the assembly can be auto incremented by changing

[assembly: AssemblyVersion("1.0.0.0")]

to

[assembly: AssemblyVersion("1.0.*")]

in the AssemblyInfo.cs file.

But how do I auto-increment the version number defined in Package.appxmanifest? That is, the version number accessible through:

 Windows.ApplicationModel.Package.Current.Id.Version

I'm using Visual Studio 2013.

Edit: Should not be flagged as duplicate, I'm asking about Package version and not Assembly version.

4条回答
一纸荒年 Trace。
2楼-- · 2020-06-12 12:56

Three line solution, versioning by date

I ran into that issue until I figured out after a lot of researches how to achieve automatic versioning in just three line in the .csproj file, here it is:

<Target Name="NugetPackAutoVersioning" AfterTargets="Build">
    <Exec Command="dotnet pack -p:PackageVersion=$([System.DateTime]::Now.ToString(&quot;yyyy.MM.dd.HHmmss&quot;)) --no-build --configuration $(Configuration) --output &quot;$(SolutionDir)nuget" />
</Target>

This will output a nuget package named like {ProjectName}.{Year}.{Month}.{Day}.{Hour}{Minute}{Second} in a "nuget" folder at the project root guaranteeing that packages built later are versioned as posteriors.

查看更多
三岁会撩人
3楼-- · 2020-06-12 12:59

Whenever you create package there is option for this functionality here is screenshot for that. All you have to do is check the Automatically increment option.

From VS Navigate Like PROJECT -> STORE -> Create App Packages -> Automatically increment

enter image description here

查看更多
叼着烟拽天下
4楼-- · 2020-06-12 13:04

In VS2017, I created a PowerShell script to pull package id and version number information by looking in a few places and update the .csproj file if needed. The help comment in the file describes how to call it from your .csproj during a build (and build the NuGet package as part of the build):

<#
.SYNOPSIS

Update version information in the .csproj file in preparation for building a nuget
package.
.DESCRIPTION

Discovers the package name and latest version. If that package exists and is newer
than the target that goes into it, do nothing; otherwise, increment the version
information in the .csproj file (without updating that .csproj file last modified
time).

The latest version gets picked from the maximum of the package/file/assembly
versions in the .csproj file and the version found on the nuget server.
.PARAMETER csproj

The path to the .csproj file to check
.PARAMETER target

The path to the build target (the DLL) that goes into the package. Used to decide whether to 
increment the version or not.
.PARAMETER packageDir

The location packages end up.
.PARAMETER nugetSite

The domain name or IP address of the nuget server to query for package version information.
.EXAMPLE

To build a nuget package on every build, add this to the csproj file:

    <Project Sdk="Microsoft.NET.Sdk">
     <Target Name="PostcompileScript" AfterTargets="Build">
       <Exec Command="powershell.exe -NonInteractive -ExecutionPolicy Unrestricted -noexit -file &quot;$(SolutionDir)UpdateCsprojPackageVersion.ps1&quot; -csproj &quot;$(ProjectPath)&quot; -target &quot;$(TargetPath)&quot; -packageDir &quot;$(SolutionDir)nuget&quot;" />
       <Exec Command="dotnet pack --no-build --include-symbols --include-source --configuration $(Configuration) --output &quot;$(SolutionDir)nuget" />
     </Target>
    </Project>
#>
param (
    [Parameter(Mandatory=$true)][string]$csproj,
    [Parameter(Mandatory=$true)][string]$target,
    [Parameter(Mandatory=$true)][string]$packageDir,
    [string]$nugetSite = "local-nuget-server"
)


$csproj = $csproj.Trim()

Write-Output "Increment package/file/assembly version in $csproj"

function ParseVersion($version)
{
    $major = 0
    $minor = 1
    $build = 0
    $revisionType = 'alpha'
    $revision = 0
    $gotData = $false
    $m = [regex]::Match($version, '(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z]*)(\d*)|\.(\d+))?')
    if ($m.Success)
    {
        $major = $m.Groups[1].Value -as [int]
        $minor = $m.Groups[2].Value -as [int]
        $build = $m.Groups[3].Value -as [int]
        if ($m.Groups[4].Success)
        {
            $revisionType = $m.Groups[4].Value.ToLower()
            $revision = $m.Groups[5].Value -as [int]
        }
        else
        {
            $revisionType = ''
            if ($m.Groups[6].Success)
            {
                $revision = $m.Groups[6].Value
            }
        }
    }

    return [Convert]::ToInt32($major, 10), [Convert]::ToInt32($minor, 10), [Convert]::ToInt32($build, 10), $revisionType, [Convert]::ToInt32($revision, 10)
}

function VersionGreaterOrEqual($major1, $minor1, $build1, $revision1, $major2, $minor2, $build2, $revision2)
{
    return ($major1 -gt $major2 -or ($major1 -eq $major2 -and ($minor1 -gt $minor2 -or ($minor1 -eq $minor2 -and ($build1 -gt $build2 -or ($build1 -eq $build2 -and $revision1 -ge $revision2))))))
}

#Read csproj (XML)
$xml = New-Object -TypeName XML
$xml.Load($csproj)
$project = $xml.SelectSingleNode("/Project")
if ($project -eq $null)
{
    $project = $xml.CreateElement("Project")
    $xml.AppendChild($project)
}
$propertyGroup = $xml.SelectSingleNode("/Project/PropertyGroup[not(@*)]")
if ($propertyGroup -eq $null)
{
    $propertyGroup = $project.AppendChild($xml.CreateElement("PropertyGroup"))
}

# Look for the package identifier in various places in the project file, as a last resort, use the project file name.
$packageId = $null
$packageidFrom = "PackageId in csproj"
$packageIdNode = $xml.SelectSingleNode("/Project/PropertyGroup[not(@*)]/PackageId")
if ($packageIdNode -ne $null)
{
    $packageId = $packageIdNode.'#text'
}

if ([String]::IsNullOrWhiteSpace($packageId))
{
    $assemblyTitle = $xml.SelectSingleNode("/Project/PropertyGroup[not(@*)]/AssemblyTitle")
    if ($assemblyTitle -ne $null)
    {
        $packageId = $assemblyTitle.'#text'
        $packageidFrom = "AssemblyTitle in csproj"
    }

    if ([String]::IsNullOrWhiteSpace($packageId))
    {
        $assemblyName = $xml.SelectSingleNode("/Project/PropertyGroup[not(@*)]/AssemblyName")
        if ($assemblyName -ne $null)
        {
            $packageId = $assemblyName.'#text'
            $packageidFrom = "AssemblyName in csproj"
        }

        if ([String]::IsNullOrWhiteSpace($packageId))
        {
            $title = $xml.SelectSingleNode("/Project/PropertyGroup[not(@*)]/Title")
            if ($title -ne $null)
            {
                $packageId = $title.'#text'
                $packageidFrom = "Title in csproj"
            }


            if ([String]::IsNullOrWhiteSpace($packageId))
            {
                $packageId = (New-Object System.IO.FileInfo($csproj)).BaseName
                $packageidFrom = "file name of csproj"
                if ($title -eq $null)
                {
                    $title = $propertyGroup.AppendChild($xml.CreateElement("Title"))
                }

                $title.'#text' = $packageId
            }

            if ($assemblyName -eq $null)
            {
                $assemblyName = $propertyGroup.AppendChild($xml.CreateElement("AssemblyName"))
            }

            $assemblyName.'#text' = $packageId
        }

        if ($assemblyTitle -eq $null)
        {
            $assemblyTitle = $propertyGroup.AppendChild($xml.CreateElement("AssemblyTitle"))
        }

        $assemblyTitle.'#text' = $packageId
    }

    if ($packageIdNode -eq $null)
    {
        $packageIdNode = $propertyGroup.AppendChild($xml.CreateElement("PackageId"))
    }

    $packageIdNode.'#text' = $packageId;
}

Write-Output "    Found Package Identifier ""$packageId"" from $packageIdFrom"

# Get the latest version from the nuget server.
# The query comes from running nuget.exe with the -Verbose option (and guessing that the search term can be a regular expression).
# The response comes back as XML
$nugetXml = New-Object -TypeName XML
$nugetXml.Load("http://$nugetSite/api/v2/Search()?`$filter=IsAbsoluteLatestVersion&searchTerm=%27^$packageId$%27&targetFramework=%27%27&includePrerelease=true")
$nugetVersionNode = $nugetXml.SelectSingleNode("feed.entry.properties.Version")
$nugetVersion = ''
if ($nugetVersionNode -ne $null)
{
    $nugetVersion = $nugetVersionNode.'#text'
}

#Retrieve Version Nodes
$packageVersionNode = $xml.SelectSingleNode("/Project/PropertyGroup[not(@*)]/PackageVersion")
if ($packageVersionNode -eq $null) {
    $packageVersionNode = $propertyGroup.AppendChild($xml.CreateElement("PackageVersion"))
}
$assemblyVersionNode = $xml.SelectSingleNode("/Project/PropertyGroup[not(@*)]/AssemblyVersion")
if ($assemblyVersionNode -eq $null) {
    $assemblyVersionNode = $propertyGroup.AppendChild($xml.CreateElement("AssemblyVersion"))
}
$fileVersionNode = $xml.SelectSingleNode("/Project/PropertyGroup[not(@*)]/FileVersion")
if ($fileVersionNode -eq $null) {
    $fileVersionNode = $propertyGroup.AppendChild($xml.CreateElement("FileVersion"))
}

$packageVersion = $packageVersionNode.'#text'
$assemblyVersion = $assemblyVersionNode.'#text'
$fileVersion = $fileVersionNode.'#text'

Write-Output "    Read versions: qat-nuget=""$nugetVersion"", package=""$packageVersion"", file=""$fileVersion"", assembly=""$assemblyVersion"""

#Split the Version Numbers
$major, $minor, $build, $revisionType, $revision = ParseVersion $nugetVersion
$paMajor, $paMinor, $paBuild, $paRevisionType, $paRevision = ParseVersion $packageVersion
$avMajor, $avMinor, $avBuild, $avRevisionType, $avRevision = ParseVersion $assemblyVersion
$fvMajor, $fvMinor, $fvBuild, $fvRevisionType, $fvRevision = ParseVersion $fileVersion

# choose between qat-nuget's package version and the package version found in the project file
if ((VersionGreaterOrEqual $paMajor $paMinor $paBuild 0 $major $minor $build 0) -and (($paRevisionType -eq '' -or $paRevisionType -gt $revisionType) -or ($paRevisionType -eq $revisionType -and $paRevision -gt $revision)))
{
    $major = $paMajor
    $minor = $paMinor
    $build = $paBuild
    $revisionType = $paRevisionType
    $revision = $paRevision
}

# Because of the way the build works, the file and assembly versions being set are for the 
# _next_ build, the package version is for the _current_ build. We err on the side of the
# package version - that is, the file and assembly version may not increment at edge cases.
# If you want to be sure that all the versions are the same in a package, you must build
# twice.

# To keep revisions for file and assembly alpha/beta/rc/release builds going in order, we 
# give the different releaseType values different base revision values.
switch($revisionType.ToLower())
{
   "rc" { $revisionDelta = 20001 }
   "beta" { $revisionDelta = 10001 }
   "alpha" { $revisionDelta = 1 }
   default { $revisionDelta = 40001 }  # for release revisions
}

# boost the version to the assembly version or the file version value if those are greater
if ((VersionGreaterOrEqual $avMajor $avMinor $avBuild $avRevision $major $minor $build ($revision + $revisionDelta)) -and (VersionGreaterOrEqual $avMajor $avMinor $avBuild $avRevision $fvMajor $fvMinor $fvBuild $fvRevision))
{
    $major = $avMajor
    $minor = $avMinor
    $build = $avBuild
    $revision = $avRevision - $revisionDelta
}
elseif (VersionGreaterOrEqual $fvMajor $fvMinor $fvBuild $fvRevision $major $minor $build ($revision + $revisionDelta))
{
    $major = $fvMajor
    $minor = $fvMinor
    $build = $fvBuild
    $revision = $fvRevision - $revisionDelta
}

if ($revision -lt 0)
{
    $revision -eq 0
}

$fileAssemblyRevision = $revision + $revisionDelta
$fileAssemblyBuild = $build


if ($revisionType -ne "")
{
    $oldPackageName = "$packageId.$major.$minor.$build-$revisionType$revision.nupkg"
}
else
{
    $oldPackageName = "$packageId.$major.$minor.$build.nupkg"
}

$oldPackage = [System.IO.Path]::Combine($packageDir, $oldPackageName)

if ([System.IO.File]::Exists($oldPackage) -and [System.IO.File]::GetLastWriteTime($oldPackage) -ge [System.IO.File]::GetLastWriteTime($target))
{
    $targetName = [System.IO.Path]::GetFileName($target)
    Write-Output "    * Not incrementing version - $oldPackageName newer than $targetName"
}
else
{
    # increment revision or build
    if ($revisionType -ne "")
    {
        $fileAssemblyRevision = $fileAssemblyRevision + 1
        $revision = $revision + 1
    }
    else
    {
        $fileAssemblyBuild = $fileAssemblyBuild + 1
        $build = $build + 1
        $fileAssemblyRevision = 0
        $revision = $revision + 0
    }


    # put the incremented version into the csproj file and save it
    $fileAssemblyVersion = "$major.$minor.$fileAssemblyBuild.$fileAssemblyRevision"
    $assemblyVersionNode.RemoveAll()
    $dummy = $assemblyVersionNode.AppendChild($xml.CreateTextNode($fileAssemblyVersion))
    $fileVersionNode.RemoveAll()
    $dummy = $fileVersionNode.AppendChild($xml.CreateTextNode($fileAssemblyVersion))
    $packageVersionNode.RemoveAll()
    if ($revisionType -eq '')
    {
        $packageVersion = "$major.$minor.$build"
    }
    else
    {
        $packageVersion = "$major.$minor.$build-$revisionType$revision"
    }

    $dummy = $packageVersionNode.AppendChild($xml.CreateTextNode($packageVersion))

    Write-Output "    Set file/assembly version to $fileAssemblyVersion, package version to $packageVersion"

    $lastWriteTime = [System.IO.File]::GetLastWriteTime($csproj)
    $xml.Save($csproj)
    [System.IO.File]::SetLastWriteTime($csproj, $lastWriteTime)
}

This scripts enforces the questionable practice of keeping the file/assembly/package version numbers in sync - we have found that practice useful. To accomplish this, revision numbers need special handling. A delta is given for beta, release candidate, and release so version numbers don't decrease when moving from package alpha-->beta, etc.

There is a trick in there because the writing of the project file comes after the build. This means the file and assembly version numbers must be kept one increment behind the package version number (the package gets built after the increment).

This script assumes you have a NuGet server to query. It shouldn't be hard to chop that code out if you don't have one.

查看更多
放荡不羁爱自由
5楼-- · 2020-06-12 13:07

In your .csproj file, you should add a property named AppxAutoIncrementPackageRevision with the value set to True.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>

    ...

    <AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>

    ...
  </PropertyGroup>

This will auto-increment the appx package version every time you build it through Visual Studio.

查看更多
登录 后发表回答