如何自动增加包版本号?

时间:2014-05-20 08:15:45

标签: c# visual-studio-2013 windows-store-apps

我意识到可以通过更改

自动增加程序集的构建/修订号
[assembly: AssemblyVersion("1.0.0.0")]

[assembly: AssemblyVersion("1.0.*")]
在AssemblyInfo.cs文件中

但是如何自动增加Package.appxmanifest中定义的版本号?也就是说,版本号可通过以下方式访问:

 Windows.ApplicationModel.Package.Current.Id.Version

我正在使用Visual Studio 2013。

编辑:不应该被标记为重复,我问的是版本,而不是汇编版本。

6 个答案:

答案 0 :(得分:11)

.csproj文件中,您应添加名为AppxAutoIncrementPackageRevision的属性,其值设置为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>

每次通过Visual Studio构建它时,都会自动增加appx包版本。

答案 1 :(得分:3)

在VS2017中,我创建了一个PowerShell脚本,通过查看几个地方来提取包ID和版本号信息,并在需要时更新.csproj文件。该文件中的帮助注释描述了如何在构建期间从.csproj调用它(并将构建NuGet包作为构建的一部分):

<#
.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)
}

这个脚本强制执行使文件/程序集/程序包版本号保持同步的可疑做法 - 我们发现这种做法很有用。为此,修订号需要特殊处理。测试版,候选发布版和发布版都有一个delta,因此从包alpha - &gt; beta等转移时,版本号不会减少。

有一个技巧,因为项目文件的编写是在构建之后。这意味着文件和程序集版本号必须保持在包版本号后面一个增量(包在增量之后构建)。

此脚本假定您有一个要查询的NuGet服务器。如果没有代码,那么编写代码并不难。

答案 2 :(得分:3)

三行解决方案,按日期进行版本控制

我遇到了这个问题,直到经过大量研究后才发现如何在.csproj文件的三行中实现自动版本控制,这里是:

<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>

这将在项目根目录的“ nuget”文件夹中输出一个名为{ProjectName}.{Year}.{Month}.{Day}.{Hour}{Minute}{Second}的nuget软件包,确保以后生成的软件包被版本化为后代。

答案 3 :(得分:2)

每当你创建包时,此功能的选项就是这里的截图。您所要做的就是选中自动增量选项。

来自VS导航,如 PROJECT - &gt;商店 - &gt;创建应用包 - &gt;自动递增

enter image description here

答案 4 :(得分:0)

dotnet软件包未在我的软件包中包含运行时/构建目标,因此我更喜欢在项目中使用Generate package on build软件包选项。

我编辑了项目文件,并在<PropertyGroup>

中添加了以下属性
<PackageVersion>$([System.DateTime]::Now.ToString(&quot;yyyy.MM.dd.HHmmss&quot;))/PackageVersion>

答案 5 :(得分:0)

使用dotnet核心开发osx

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