如何自动增加包版本号?

问题描述 投票:0回答:5

我意识到程序集的构建/修订号可以通过更改来自动递增

[assembly: AssemblyVersion("1.0.0.0")]

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

在 AssemblyInfo.cs 文件中。

但是如何自动递增 Package.appxmanifest 中定义的版本号?即,可以通过以下方式获取版本号:

 Windows.ApplicationModel.Package.Current.Id.Version

我使用的是 Visual Studio 2013。

c# visual-studio-2013 windows-store-apps
5个回答
40
投票

三行,按日期版本控制

我遇到了这个问题,直到我经过大量研究后弄清楚如何在

.csproj
文件中仅用三行即可实现自动版本控制。这是:

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

这将在项目根目录的“nuget”文件夹中输出一个名为

{ProjectName}.{Year}.{Month}.{Day}.{Hour}{Minute}
的 NuGet 包,确保稍后构建的包被版本化为后验包。


17
投票

dotnet pack 不包括我的包中的运行时/构建目标,因此我更喜欢在项目中使用

Generate package on build
包选项。

我编辑了我的项目文件并在

<PropertyGroup>

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

13
投票

在您的

.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 包版本时,这都会自动递增。


3
投票

在 Visual Studio 2017 中,我创建了一个 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)
}

此脚本强制执行保持文件/程序集/包版本号同步的可疑做法 - 我们发现这种做法很有用。为了实现这一点,修订号需要特殊处理。为 beta、候选版本和发布版本提供了增量,因此当从包 alpha → beta 等移动时,版本号不会减少。

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

此脚本假设您有一个要查询的 NuGet 服务器。如果你没有代码,删除该代码应该不难。


2
投票

每当您创建包时,都会有一个用于此功能的选项,下面是该功能的屏幕截图。您所要做的就是选中自动增量选项。

在 Visual Studio 中,像菜单一样导航 ProjectStore创建应用程序包自动递增

Enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.