我在以 SVN 作为源代码控制的示例项目中使用 CCNET。CCNET 配置为在每次签入时创建构建。CCNET 使用 MSBuild 构建源代码。
我想AssemblyInfo.cs在编译时使用最新的修订号来生成。如何从 subversion 中检索最新版本并使用 CCNET 中的值?
编辑:我没有使用 NAnt - 只有 MSBuild。
我在以 SVN 作为源代码控制的示例项目中使用 CCNET。CCNET 配置为在每次签入时创建构建。CCNET 使用 MSBuild 构建源代码。
我想AssemblyInfo.cs在编译时使用最新的修订号来生成。如何从 subversion 中检索最新版本并使用 CCNET 中的值?
编辑:我没有使用 NAnt - 只有 MSBuild。
CruiseControl.Net 1.4.4 现在有一个Assembly Version Labeller,它生成与 .Net 程序集属性兼容的版本号。
在我的项目中,我将其配置为:
<labeller type="assemblyVersionLabeller" incrementOnFailure="true" major="1" minor="2"/>
(警告:assemblyVersionLabeller在实际的提交触发构建发生之前,不会开始生成基于 svn 修订的标签。)
然后使用MSBuildCommunityTasks.AssemblyInfo从我的 MSBuild 项目中使用它:
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Target Name="BeforeBuild">
<AssemblyInfo Condition="'$(CCNetLabel)' != ''" CodeLanguage="CS" OutputFile="Properties\AssemblyInfo.cs"
AssemblyTitle="MyTitle" AssemblyCompany="MyCompany" AssemblyProduct="MyProduct"
AssemblyCopyright="Copyright © 2009" ComVisible="false" Guid="some-random-guid"
AssemblyVersion="$(CCNetLabel)" AssemblyFileVersion="$(CCNetLabel)"/>
</Target>
为了完整起见,使用 NAnt 而不是 MSBuild 的项目同样容易:
<target name="setversion" description="Sets the version number to CruiseControl.Net label.">
<script language="C#">
<references>
<include name="System.dll" />
</references>
<imports>
<import namespace="System.Text.RegularExpressions" />
</imports>
<code><![CDATA[
[TaskName("setversion-task")]
public class SetVersionTask : Task
{
protected override void ExecuteTask()
{
StreamReader reader = new StreamReader(Project.Properties["filename"]);
string contents = reader.ReadToEnd();
reader.Close();
string replacement = "[assembly: AssemblyVersion(\"" + Project.Properties["CCNetLabel"] + "\")]";
string newText = Regex.Replace(contents, @"\[assembly: AssemblyVersion\("".*""\)\]", replacement);
StreamWriter writer = new StreamWriter(Project.Properties["filename"], false);
writer.Write(newText);
writer.Close();
}
}
]]>
</code>
</script>
<foreach item="File" property="filename">
<in>
<items basedir="..">
<include name="**\AssemblyInfo.cs"></include>
</items>
</in>
<do>
<setversion-task />
</do>
</foreach>
</target>
你基本上有两个选择。您可以编写一个简单的脚本来启动并解析来自
svn.exe 信息 --revision HEAD
获取修订号(然后生成 AssemblyInfo.cs 非常简单)或仅使用 CCNET 插件。这里是:
SVN Revision Labeller是 CruiseControl.NET 的插件,它允许您根据 Subversion 工作副本的修订号为您的构建生成 CruiseControl 标签。这可以使用前缀和/或主要/次要版本号进行自定义。
我更喜欢第一个选项,因为它只有大约 20 行代码:
using System;
using System.Diagnostics;
namespace SvnRevisionNumberParserSample
{
class Program
{
static void Main()
{
Process p = Process.Start(new ProcessStartInfo()
{
FileName = @"C:\Program Files\SlikSvn\bin\svn.exe", // path to your svn.exe
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = "info --revision HEAD",
WorkingDirectory = @"C:\MyProject" // path to your svn working copy
});
// command "svn.exe info --revision HEAD" will produce a few lines of output
p.WaitForExit();
// our line starts with "Revision: "
while (!p.StandardOutput.EndOfStream)
{
string line = p.StandardOutput.ReadLine();
if (line.StartsWith("Revision: "))
{
string revision = line.Substring("Revision: ".Length);
Console.WriteLine(revision); // show revision number on screen
break;
}
}
Console.Read();
}
}
}
我在谷歌代码上找到了这个项目。这是CCNET生成标签的插件CCNET。
DLL已经过测试,但CCNET 1.3它适用CCNET 1.4于我。我成功地使用这个插件来标记我的构建。
现在将其传递给MSBuild...
如果您更喜欢在配置上执行它MSBuild,CCNet看起来MSBuild社区任务扩展的SvnVersion任务可能会成功。
我编写了一个 NAnt 构建文件来处理解析 SVN 信息和创建属性。然后,我将这些属性值用于各种构建任务,包括在构建上设置标签。我将此目标与 lubos hasko 提到的 SVN Revision Labeller 结合使用,效果很好。
<target name="svninfo" description="get the svn checkout information">
<property name="svn.infotempfile" value="${build.directory}\svninfo.txt" />
<exec program="${svn.executable}" output="${svn.infotempfile}">
<arg value="info" />
</exec>
<loadfile file="${svn.infotempfile}" property="svn.info" />
<delete file="${svn.infotempfile}" />
<property name="match" value="" />
<regex pattern="URL: (?'match'.*)" input="${svn.info}" />
<property name="svn.info.url" value="${match}"/>
<regex pattern="Repository Root: (?'match'.*)" input="${svn.info}" />
<property name="svn.info.repositoryroot" value="${match}"/>
<regex pattern="Revision: (?'match'\d+)" input="${svn.info}" />
<property name="svn.info.revision" value="${match}"/>
<regex pattern="Last Changed Author: (?'match'\w+)" input="${svn.info}" />
<property name="svn.info.lastchangedauthor" value="${match}"/>
<echo message="URL: ${svn.info.url}" />
<echo message="Repository Root: ${svn.info.repositoryroot}" />
<echo message="Revision: ${svn.info.revision}" />
<echo message="Last Changed Author: ${svn.info.lastchangedauthor}" />
</target>
我目前正在使用我的cmdnetsvnrev工具通过 prebuild-exec 任务“手动”执行此操作,但如果有人知道更好的 ccnet 集成方式,我会很高兴听到 :-)
自定义 csproj 文件以自动生成 AssemblyInfo.cs
http://www.codeproject.com/KB/dotnet/Customizing_csproj_files.aspx每次我们创建一个新的 C# 项目时,Visual Studio 都会为我们放置 AssemblyInfo.cs 文件。该文件定义程序集元数据,如其版本、配置或生产者。
找到了使用 MSBuild 自动生成 AssemblyInfo.cs 的上述技术。将很快发布样品。
我不确定这是否适用于 CCNET,但我已经为 CodePlex 上的Build Version Increment项目创建了一个SVN 版本插件。该工具非常灵活,可以设置为使用 svn 修订版自动为您创建版本号。它不需要编写任何代码或编辑 xml,所以耶!
我希望这会有所帮助!
我的方法是使用前面提到的 ccnet 插件和一个 nant echo 任务来生成一个VersionInfo.cs只包含版本属性的文件。我只需要将VersionInfo.cs文件包含到构建中
echo 任务只是将我给它的字符串输出到一个文件中。
如果有类似的 MSBuild 任务,您可以使用相同的方法。这是我使用的小任务:
<target name="version" description="outputs version number to VersionInfo.cs">
<echo file="${projectdir}/Properties/VersionInfo.cs">
[assembly: System.Reflection.AssemblyVersion("$(CCNetLabel)")]
[assembly: System.Reflection.AssemblyFileVersion("$(CCNetLabel)")]
</echo>
</target>
试试这个:
<ItemGroup>
<VersionInfoFile Include="VersionInfo.cs"/>
<VersionAttributes>
[assembly: System.Reflection.AssemblyVersion("${CCNetLabel}")]
[assembly: System.Reflection.AssemblyFileVersion("${CCNetLabel}")]
</VersionAttributes>
</ItemGroup>
<Target Name="WriteToFile">
<WriteLinesToFile
File="@(VersionInfoFile)"
Lines="@(VersionAttributes)"
Overwrite="true"/>
</Target>
请注意,我对 MSBuild 不是很熟悉,所以我的脚本可能无法开箱即用,需要更正......
基于 skolimas 解决方案,我更新了 NAnt 脚本以更新 AssemblyFileVersion。感谢 skolima 的代码!
<target name="setversion" description="Sets the version number to current label.">
<script language="C#">
<references>
<include name="System.dll" />
</references>
<imports>
<import namespace="System.Text.RegularExpressions" />
</imports>
<code><![CDATA[
[TaskName("setversion-task")]
public class SetVersionTask : Task
{
protected override void ExecuteTask()
{
StreamReader reader = new StreamReader(Project.Properties["filename"]);
string contents = reader.ReadToEnd();
reader.Close();
// replace assembly version
string replacement = "[assembly: AssemblyVersion(\"" + Project.Properties["label"] + "\")]";
contents = Regex.Replace(contents, @"\[assembly: AssemblyVersion\("".*""\)\]", replacement);
// replace assembly file version
replacement = "[assembly: AssemblyFileVersion(\"" + Project.Properties["label"] + "\")]";
contents = Regex.Replace(contents, @"\[assembly: AssemblyFileVersion\("".*""\)\]", replacement);
StreamWriter writer = new StreamWriter(Project.Properties["filename"], false);
writer.Write(contents);
writer.Close();
}
}
]]>
</code>
</script>
<foreach item="File" property="filename">
<in>
<items basedir="${srcDir}">
<include name="**\AssemblyInfo.cs"></include>
</items>
</in>
<do>
<setversion-task />
</do>
</foreach>
</target>
不知道我在哪里找到这个。但我在互联网上的“某处”找到了这个。
这会在构建发生之前更新所有 AssemblyInfo.cs 文件。
奇迹般有效。我所有的 exe 和 dll 都显示为 1.2.3.333(如果“333”是当时的 SVN 修订版。)(并且 AssemblyInfo.cs 文件中的原始版本被列为“1.2.3.0”)
$(ProjectDir) (我的 .sln 文件所在的位置)
$(SVNToolPath) (指向 svn.exe)
是我的自定义变量,它们的声明/定义未在下面定义。
http://msbuildtasks.tigris.org/ 和/或 https://github.com/loresoft/msbuildtasks 具有( FileUpdate 和 SvnVersion )任务。
<Target Name="SubVersionBeforeBuildVersionTagItUp">
<ItemGroup>
<AssemblyInfoFiles Include="$(ProjectDir)\**\*AssemblyInfo.cs" />
</ItemGroup>
<SvnVersion LocalPath="$(MSBuildProjectDirectory)" ToolPath="$(SVNToolPath)">
<Output TaskParameter="Revision" PropertyName="MySubVersionRevision" />
</SvnVersion>
<FileUpdate Files="@(AssemblyInfoFiles)"
Regex="(\d+)\.(\d+)\.(\d+)\.(\d+)"
ReplacementText="$1.$2.$3.$(MySubVersionRevision)" />
</Target>
编辑 - - - - - - - - - - - - - - - - - - - - - - - - - -
在您的 SVN 修订号达到 65534 或更高版本后,上述操作可能会开始失败。
看:
这是解决方法。
<FileUpdate Files="@(AssemblyInfoFiles)"
Regex="AssemblyFileVersion\("(\d+)\.(\d+)\.(\d+)\.(\d+)"
ReplacementText="AssemblyFileVersion("$1.$2.$3.$(SubVersionRevision)" />
结果应该是:
在 Windows/资源管理器//文件/属性中……。
程序集版本将为 1.0.0.0。
如果 333 是 SVN 修订版,则文件版本将为 1.0.0.333。
当心。用于内部版本号的结构很短,因此您对修订可以达到多高有一个上限。
在我们的例子中,我们已经超过了限制。
如果您尝试输入内部版本号 99.99.99.599999,则文件版本属性实际上将显示为 99.99.99.10175。