Как я могу использовать MSBuild для обновления информации о версии только при изменении сборки?

У меня есть требование установить несколько проектов веб-настройки (с использованием VS2005 и ASP.Net/C#) в одну виртуальную папку. Проекты имеют общие ссылки на сборки (все файловые системы структурированы для использования одной и той же папки bin), что делает развертывание изменений в этих сборках проблематичным, поскольку установщик MS будет перезаписывать сборки только в том случае, если текущая установленная версия старше версии в MSI.

Я не утверждаю, что пессимистическая схема установки неверна - только то, что она создает проблемы в среде, с которой мне было поручено работать. Поскольку существует значительное количество общих сборок и значительное количество разработчиков, которые могут изменить общую сборку, но забывают обновить ее номер версии, попытка управления версиями вручную в конечном итоге приведет к огромной путанице во время установки.

С другой стороны, важно не обновлять номера версий спонтанно, а заменять все общие сборки на каждую установку, поскольку это может (по крайней мере временно) скрыть случаи где были внесены фактические изменения.

Тем не менее, то, что я ищу, - это средство для обновления информации о версии сборки (желательно с использованием MSBuild) только в тех случаях, когда компоненты сборки (модули кода, ресурсы и т. Д.) Действительно изменились / изменились.

Я нашел несколько ссылок, которые хотя бы частично относятся к делу здесь (задача AssemblyInfo в MSDN) и здесь (похоже на то, что мне нужно, но старше двух лет и без четкого решения).

Моя команда также использует контроль версий TFS, поэтому автоматизированное решение, вероятно, должно включать средства, с помощью которых AssebmlyInfo можно будет извлекать / загружать во время сборки.

Любая помощь приветствуется.

Заранее спасибо.


person Jared    schedule 21.10.2008    source источник


Ответы (3)


Я не могу ответить на все ваши вопросы, так как у меня нет опыта работы с TFS.

Но я могу порекомендовать лучший подход для обновления ваших файлов AssemblyInfo.cs, чем использование задачи AssemblyInfo. Эта задача, похоже, просто воссоздает стандартный файл AssemblyInfo с нуля и теряет все настраиваемые части, которые вы могли добавить.

По этой причине я предлагаю вам изучить задачу FileUpdate из проекта MSBuild Community Tasks. Он может искать конкретное содержимое в файле и заменять его, например:

<FileUpdate 
Files="$(WebDir)\Properties\AssemblyInfo.cs"
Regex="(\d+)\.(\d+)\.(\d+)\.(\d+)"
ReplacementText="$(Major).$(ServicePack).$(Build).$(Revision)" 
Condition="'$(Configuration)' == 'Release'"
/>

Есть несколько способов контролировать приращение номера сборки. Поскольку я хочу, чтобы номер сборки увеличивался только в том случае, если сборка была полностью успешной, я использую двухэтапный метод:

  • прочитать число из текстового файла (единственное, что в файле - это число) и добавить 1, не изменяя файл;
  • в качестве последнего шага в процессе сборки, если все прошло успешно, сохраните увеличенное число обратно в текстовый файл.

Существуют такие задачи, как ReadLinesFromFile, которые могут вам в этом помочь, но мне показалось, что проще всего написать небольшую настраиваемую задачу:

using System;
using System.IO;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace CredibleCustomBuildTasks
{
    public class IncrementTask : Task
    {
        [Required]
        public bool SaveChange { get; set; }

        [Required]
        public string IncrementFileName { get; set; }

        [Output]
        public int Increment { get; set; }

        public override bool Execute()
        {
            if (File.Exists(IncrementFileName))
            {
                string lines = File.ReadAllText(IncrementFileName);
                int result;
                if(Int32.TryParse(lines, out result))
                {
                    Increment = result + 1;
                }
                else
                {
                    Log.LogError("Unable to parse integer in '{0}' (contents of {1})");
                    return false;
                }
            }
            else
            {
                Increment = 1;
            }

            if (SaveChange)
            {
                File.Delete(IncrementFileName);
                File.WriteAllText(IncrementFileName, Increment.ToString());
            }
            return true;
        }
    }
}

Я использую это перед FileUpdateTask, чтобы получить следующий номер сборки:

<IncrementTask 
IncrementFileName="$(BuildNumberFile)" 
SaveChange="false">
  <Output TaskParameter="Increment" PropertyName="Build" />
</IncrementTask>

и в качестве последнего шага (перед тем, как уведомить других) в сборке:

<IncrementTask 
IncrementFileName="$(BuildNumberFile)" 
SaveChange="true"
Condition="'$(Configuration)' == 'Release'" />

Другой вопрос о том, как обновить номер версии только при изменении исходного кода, сильно зависит от того, как процесс сборки взаимодействует с системой управления версиями. Обычно проверка изменений исходного файла должна инициировать сборку с непрерывной интеграцией. Это тот, который нужно использовать для обновления соответствующего номера версии.

person David White    schedule 22.10.2008

Я написал одну индивидуальную задачу, вы можете сослаться на приведенный ниже код. Он создаст утилиту, в которую вы можете передать информацию о сборке, путь Major, minor и номер сборки. вы можете изменить его, чтобы получить номер редакции. Поскольку в моем случае эту задачу выполнил разработчик, я искал ее и снова заменял целую строку.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace UpdateVersion
{
    class SetVersion
    {
        static void Main(string[] args)
        {
            String FilePath = args[0];
            String MajVersion=args[1];
            String MinVersion = args[2];
            String BuildNumber = args[3];
            string RevisionNumber = null;

            StreamReader Reader = File.OpenText(FilePath);
            string contents = Reader.ReadToEnd();
            Reader.Close();

            MatchCollection match = Regex.Matches(contents, @"\[assembly: AssemblyVersion\("".*""\)\]", RegexOptions.IgnoreCase);
            if (match[0].Value != null)
            {
                string strRevisionNumber = match[0].Value;

                RevisionNumber = strRevisionNumber.Substring(strRevisionNumber.LastIndexOf(".") + 1, (strRevisionNumber.LastIndexOf("\"")-1) - strRevisionNumber.LastIndexOf("."));

                String replaceWithText = String.Format("[assembly: AssemblyVersion(\"{0}.{1}.{2}.{3}\")]", MajVersion, MinVersion, BuildNumber, RevisionNumber);
                string newText = Regex.Replace(contents, @"\[assembly: AssemblyVersion\("".*""\)\]", replaceWithText);

                StreamWriter writer = new StreamWriter(FilePath, false);
                writer.Write(newText);
                writer.Close();
            }
            else
            {
                Console.WriteLine("No matching values found");
            }
        }
    }
}
person Community    schedule 25.06.2009

Ненавижу это говорить, но похоже, что вы делаете это неправильно. Гораздо проще, если вы создаете версии сборки на лету, а не пытаетесь их исправлять.

Взгляните на https://sbarnea.com/articles/easy-windows-build-versioning/

Почему я думаю, что вы делаете это неправильно? * Сборка не должна изменять номер версии * если вы создаете один и тот же набор изменений дважды, вы должны получить те же номера сборки * если вы поместите номер сборки в номер сборки, который Microsoft называет (правильное имя будет уровнем PATCH), вы в конечном итоге достигнете 65535 ограничение.

person sorin    schedule 08.09.2015