1. Create custom task by Visual Studio:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace MyBuildExtensions
{
public class AssemblyInfo : Task
{
private const string Company = "Company name";
private const string Copyright = "© 19xx - {0} Company name";
[Required]
public string FileNames { get; set; }
[Required]
public int MajorVersion { get; set; }
[Required]
public int MinorVersion { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
public override bool Execute()
{
Log.LogMessage("FileName: {0}", FileNames);
DateTime now = DateTime.Now;
int year = now.Year;
string copyright = string.Format(Copyright, year);
Log.LogMessage("Copyright: {0}", copyright);
string buildNumber = now.ToString("yyMM");
string revision = now.ToString("dd");
string version = string.Format("{0}.{1}.{2}.{3}", MajorVersion, MinorVersion, buildNumber, revision);
Log.LogMessage("Version: {0}", version);
List<string> fileList = new List<string>();
if (FileNames.Contains(";"))
{
string[] files = FileNames.Split(';');
fileList.AddRange(files);
}
else
{
fileList.Add(FileNames);
}
bool ok = false;
foreach (string fileName in fileList)
{
ok = ReplaceProperties(fileName, version, copyright);
if (!ok)
{
break;
}
}
return ok;
}
private bool ReplaceProperties(string fileName, string assemblyVersion, string assemblyCopyright)
{
bool ok = false;
// remove readonly
FileAttributes currentAttr = File.GetAttributes(fileName);
File.SetAttributes(fileName, FileAttributes.Normal);
// read file
string content = File.ReadAllText(fileName, Encoding.UTF8);
// replace properties
ok = ReplaceProperty(ref content, Title, "AssemblyTitle", fileName);
if (ok)
{
ok = ReplaceProperty(ref content, Title, "AssemblyProduct", fileName);
}
if (ok)
{
ok = ReplaceProperty(ref content, Description, "AssemblyDescription", fileName);
}
if (ok)
{
ok = ReplaceProperty(ref content, assemblyCopyright, "AssemblyCopyright", fileName);
}
if (ok)
{
ok = ReplaceProperty(ref content, assemblyVersion, "AssemblyVersion", fileName);
}
if (ok)
{
ok = ReplaceProperty(ref content, assemblyVersion, "AssemblyFileVersion", fileName);
}
// write back to file
File.WriteAllText(fileName, content, Encoding.UTF8);
// set readonly back
File.SetAttributes(fileName, currentAttr);
return ok;
}
private bool ReplaceProperty(ref string content, string newValue, string propertyName, string fileName)
{
string pattern = string.Format("{0}\\(\".*\"\\)", propertyName);
string replacement = string.Format("{0}(\"{1}\")", propertyName, newValue);
var re = new Regex(pattern, RegexOptions.Multiline);
if (re.IsMatch(content))
{
content = re.Replace(content, replacement);
}
else
{
Log.LogError("The content of file {0} does not contain {1} attribute!", fileName, propertyName);
return false;
}
return true;
}
}
}
You must add those references first:
- Microsoft.Build.Framework.dll
- Microsoft.Build.Utilities.v3.5.dll
2. Copy DLL that contains created task to Team Build server.
For example: C:\Program Files\MSBuild\ExtensionPack\MyBuildExtensions.dll
3. Modify project Team Build Type file (TFSBuild.proj):
<UsingTask AssemblyFile="$(MSBuildExtensionsPath)\\ExtensionPack\\MyBuildExtensions.dll" TaskName="MyBuildExtensions.AssemblyInfo"/>
<Target Name="BeforeCompile">
<!-- specify assembly files to include for AssemblyInfo Task -->
<CreateItem Include="$(SourcesRoot)\**\AssemblyInfo.*">
<Output ItemName="AssemblyInfoFiles" TaskParameter="Include"/>
</CreateItem>
<MyBuildExtensions.AssemblyInfo
FileNames="@(AssemblyInfoFiles)"
MajorVersion="1"
MinorVersion="2"
Title="Product title"
Description="Product description">
</MyBuildExtensions.AssemblyInfo>
</Target>
Where $(SourcesRoot) is custom defined property that points to the sources folder.
My versioning is in the format: Minor.Major.YYMM.DD