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

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

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

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

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

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

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

Любая помощь будет принята с благодарностью.

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

Ответы [ 3 ]

10 голосов
/ 22 октября 2008

Я не могу ответить на все ваши вопросы, так как у меня нет опыта работы с 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'" />

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

0 голосов
/ 08 сентября 2015

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

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

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

0 голосов
/ 25 июня 2009

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

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");
            }
        }
    }
}
...