Управление версиями в объектной модели клиента TFS

Загрузить пример программного кода

Эта статья служит продолжением документа под названием «Использование объектной модели клиента Team Foundation Server», составленного участниками группы Visual Studio ALM Rangers для выпуска за август 2012 года (msdn.microsoft.com/magazine/jj553516). Ранее мы представили объектную модель клиента Team Foundation Server (TFS), теперь же я представлю API для управления версиями.

Напоминаю, что ALM Rangers — это группа экспертов, которые способствуют взаимодействию группы разработчиков продукта Visual Studio, служб Microsoft Services и сообщества специалистов Microsoft Most Valuable Professional (MVP). Усилиями этой группы выявляются отсутствующие функциональные возможности, устраняются возможные преграды для внедрения ПО и публикуются рекомендации и руководства, в основе которых лежит практический опыт.

Если кто-нибудь попросит вас объяснить, что такое TFS, с высокой долей вероятности вы уже в первых предложениях упомянете об управлении версиями. Несмотря на то что управление версиями действительно играет важную роль в TFS, на рисунке 1 видно, что возможности TFS намного шире. Как и многие другие функции TFS, подсистема управления версиями доступна через объектную модель TFS. Эта доступность обеспечивает расширяемую модель, которую вы можете использовать в собственных инструментах и процессах.

Рисунок 1. ВозможностиTeam Foundation Server

Сборки и пространства имен

Перед использованием функциональных возможностей, предоставляемых объектной моделью TFS, необходимо знать требуемые сборки и пространства имен. Вы наверняка помните, что в первой статье использовалось пространство имен Microsoft.TeamFoundation.Client. Это пространство имен содержит классы и методы, необходимые для соединения с сервером конфигурации TFS, а расположены они в сборке с идентичным именем. Это пространство имен является основой разработки на базе объектной модели TFS.

При работе с системой управления версиями также необходимо использовать пространство имен Microsoft.TeamFoundation.VersionControl.Client. Это пространство имен содержит классы, необходимые для взаимодействия с системой управления версиями в TFS. Использование API в этом пространстве имен обеспечивает доступ к файлам и папкам, а также применение отложенного внесения изменений, слияния объектов, поддержки ветвей и т. п. Класс VersionControlServer является основным классом в этом пространстве имен, который предоставляет доступ к репозиторию системы контроля версий в TFS.

Простой пример начала работы

Класс VersionControlServer содержит множество свойств, методов и событий, предназначенных для взаимодействия с системой управления версиями в TFS. Начну с простого примера: получение идентификатора новейшего набора изменений.

Для взаимодействия с большинством API, которые предоставляются в модели TFS, предусмотрены три основных шага:

  1. Подключение к серверу конфигурации TFS.
  2. Получение ссылки на службу TFS, которую вы планируете использовать.
  3. Использование различных свойств, методов и событий, предоставляемых службой.

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

Создайте новый экземпляр TeamProjectPicker и отобразите его с помощью метода ShowDialog:

  1. private TfsTeamProjectCollection _tpc;
  2. using (var picker = new TeamProjectPicker(TeamProjectPickerMode.NoProject, false))
  3. {
  4.   if (picker.ShowDialog()== DialogResult.OK)
  5.   {
  6.     _tpc = picker.SelectedTeamProjectCollection;
  7.   }
  8. }

Этот код отображает диалоговое окно, похожее на изображенное на рисунке 2.

The TeamProjectPicker Dialog
Рисунок 2. Диалоговое окно TeamProjectPicker

Нажатие кнопки Connect (Подключить) возвращает экземпляр коллекции TfsTeamProjectCollection, представляющий собой выбранную коллекцию Team Project Collection (TPC). Если вы предпочитаете использовать для подключения к TFS более программно-ориентированный подход, не требующий взаимодействия с пользователем, обратитесь к примерам из августовской статьи.

Полученную ссылку на коллекцию TfsTeamProjectCollection можно использовать для получения экземпляра службы VersionControlServer:

 

  1. var vcs = _tpc.GetService<VersionControlServer>();

Получив ссылку на службу, можно использовать методы, предоставленные этой службой:

  1. var latestId = vcs.GetLatestChangesetId();

Это простой пример, однако в нем демонстрируются основные этапы взаимодействия с системой управления версиями в TFS. Но далеко не все приложения настолько просты.

Получение новейшего кода

Один из общих сценариев использования системы управления версиями — получение новейшего исходного кода из репозитория. Работая в Visual Studio, вы обычно получаете новейший исходный код, щелкнув правой кнопкой мыши файл или папку в проводнике системы управления версиями Source Control Explorer (SCE) и выбрав пункт Get Latest Version (Получить новейшую версию). Чтобы эта функция работала правильно, также необходимо выбрать сопоставленное рабочее пространство. Выбранное пространство определяет место хранения новейшего исходного кода, загружаемого с сервера.

Чтобы получить новейший исходный код программным способом, выполните следующие действия:

  1. Подключитесь к серверу конфигурации TFS.
  2. Получите ссылку на службу управления версиями.
  3. Воспользуйтесь существующим рабочим пространством или создайте новое, временное рабочее пространство.
  4. Сопоставьте рабочее пространство с локальной папкой.
  5. Загрузите нужные файлы из рабочего пространства.

Основываясь на предыдущем примере добавьте код, представленный на рисунке 3.

Рисунок 3. Получение новейшего кода из системы управления версиями

  1. // Создание временного рабочего пространства
  2. var workspace = vcs.CreateWorkspace(Guid.NewGuid().ToString(),
  3.   _tpc.AuthorizedIdentity.UniqueName,
  4.   "Temporary workspace for file retrieval");
  5. // Для этого рабочего пространства папка на сервере сопоставляется с локальной папкой
  6. workspace.Map("$/Demo/TFS_VC_API", @"C:\Dev\Test");
  7. // Создание ItemSpec для определения списка получаемых файлов и папок
  8. // Получение всего содержимого папки на сервере
  9. var fileRequest = new GetRequest(
  10.   new ItemSpec("$/Demo/TFS_VC_API", RecursionType.Full),
  11.   VersionSpec.Latest);
  12. // Получение новейшего кода
  13. var results = workspace.Get(fileRequest, GetOptions.GetAll | GetOptions.Overwrite);

Если рабочее пространство уже существует и вы хотите его использовать, то замените строки 1-4 в рисунке 3 следующими строками:

  1. // Получение ссылки на существующее рабочее пространство.
  2. // Здесь оно называется DEMO_Workspace
  3. var workspace = vcs.GetWorkspace("DEMO_Workspace", _tpc.AuthorizedIdentity.UniqueName);

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

Вам не потребуется заниматься программным сопоставлением этого рабочего пространства, поэтому можете также удалить строки 5 и 6.

Определение загружаемых файлов и папок

Как вы наверняка ожидаете, в TFS предусмотрены несколько API для опроса сервера управления версиями с целью получения отдельных элементов и конкретных версий элементов. Когда я создавал новый экземпляр GetRequest в предыдущем примере, мне нужно было указать экземпляр ItemSpec. ItemSpec — это аббревиатура словосочетания item specification (спецификация элементов), она служит для описания набора файлов или папок. Эти элементы могут располагаться на вашем локальном компьютере или на сервере управления версиями. В этом конкретном примере я создаю ItemSpec, чтобы возвратить все файлы в папке $/Demo/TFS_VC_API на сервере.

Второй параметр использованного здесь конструктора ItemSpec служит для указания типа рекурсии RecursionType, и он может принимать следующие значения: None (Нет), Full (Полная) или OneLevel (Один уровень). Это значение определяет, насколько глубоко API должен исследовать уровни при запросе элементов. Если параметру RecursionType присвоить значение OneLevel, то будут опрошены и возвращены только элементы наиболее высокого уровня по отношению к ItemSpec. Указав значение Full, можно опросить и вернуть элементы не только верхнего уровня, но и всех нижележащих уровней (и опять расположение этих уровней определяется относительно ItemSpec).

Параметр ItemSpec позволяет при запросе указать название и местоположение элементов в системе управления версиями, ограничивая тем самым круг исследуемых элементов. В то же самое время параметр VersionSpec, представляющий собой аббревиатуру словосочетания version specification (спецификация версии), позволяет указывать версию для ограничения количества наборов элементов. VersionSpec является абстрактным классом, поэтому его можно инстанцировать напрямую. TFS содержит несколько реализаций VersionSpec, которые можно использовать при опросе системы управления версиями. На рисунке 4 приведен список различных реализаций класса VersionSpec, предлагаемых в TFS 2012 по умолчанию.

 

Figure 4 VersionSpec Types

VersionSpec Описание
ChangesetVersionSpec Служит для указания версии на основе номера набора изменений.
DateVersionSpec Служит для указания версии на основе отметки даты или времени.
LabelVersionSpec Служит для указания версии на основе метки.
LatestVersionSpec Обозначает новейшую действительную версию в репозитории.
WorkspaceVersionSpec Служит для указания версии на основе имени или владельца рабочего пространства.

Возвращаясь к предыдущему примеру создания GetRequest, замечу, что я указал VersionSpec.Latest в качестве моей спецификации версии. VersionSpec.Latest представляет собой просто ссылку на единственный экземпляр LatestVersionSpec, предоставляемую только для удобства. Например, чтобы получить код с помощью конкретной метки, создайте экземпляр LabelVersionSpec:

  1. var fileRequest = new GetRequest(
  2.   new ItemSpec("$/Demo/TFS_VC_API", RecursionType.Full),
  3.   new LabelVersionSpec("MyLabel"));

Проверка программного кода

Теперь, когда вам известны примеры выявления и получения отдельных элементов с сервера управлениями версиями, давайте рассмотрим, как можно проверить исходный код. Если пользоваться терминами TFS, то проверка элемента означает приостановку изменений в этом элементе. Чтобы приостановить изменения для элементов отдельного рабочего пространства, можно вызвать метод Workspace.PendEdit. Метод PendEdit имеет девять возможных перегрузок, каждая из которых требует путь или массив путей, а также несколько дополнительных параметров. Одним из дополнительных параметров является RecursionType, механизм работы которого полностью совпадает с ранее описанным параметром ItemSpec.

Например, чтобы проверить все файлы C# (.cs), сделайте следующий вызов:

  1. // В этом примере предполагается, что мы получили ссылку
  2. // на существующее рабочее пространство в предыдущих примерах
  3. var results = workspace.PendEdit("$/Demo/TFS_VC_API/*.cs", RecursionType.Full);

В этом примере я запрашиваю у TFS приостановку изменения всех файлов C# (с помощью знака подстановки *.cs), расположенных в серверной папке $/Demo/TFS_VC_API. Поскольку для параметра RecursionType я указал значение Full, я проверю все файлы C# во всех папках, расположенных ниже указанного пути. Сигнатура метода, использованная в этом примере, также позволит загрузить все проверенные файлы в локальный каталог, путь к которому сопоставлен с указанным рабочим пространством. Вы можете использовать одну из перегруженных версий этого метода, которая принимает аргументы типа PendChangesOptions, и указать PendChangesOption.Silent для отмены загрузки всех файлов при приостановке изменений. Значение, возвращаемое в результатах выполнения этой команды, содержит количество загруженных элементов, поскольку я сделал вызов к PendEdit.

Изменение файлов — не единственное действие, которое можно приостановить с помощью системы управления версиями. Также имеются следующие методы, поддерживающие приостановку:

  • Добавление с помощью PendAdd.
  • Создание ветвей с помощью PendBranch.
  • Удаление с помощью PendDelete.
  • Получение свойств с помощью PendPropertyName.
  • Переименование с помощью PendRename.
  • Отмена удаления с помощью PendUndelete.

Например, следующий код выполняет приостановку создания новой ветви под названием Dev из папки Main:

  1. // В этом примере предполагается, что мы получили ссылку
  2. // на существующее рабочее пространство в предыдущих примерах
  3.  var results = workspace.PendBranch("$/Demo/TFS_VC_API/Main",  
  4.  "$/Demo/TFS_VC_API/Dev", VersionSpec.Latest);

Создание ветвей и слияние с помощью API мы рассмотрим в будущей статье.

Регистрация изменений

После внесения изменений в один или несколько проверенных файлов, их можно зарегистрировать в системе с помощью метода Workspace.CheckIn. Однако перед вызовом метода CheckIn необходимо сначала получить список приостановленных изменений для рабочего пространства, вызвав метод Workspace.GetPendingChanges. Если не указать никаких параметров для метода GetPendingChanges, то будут возвращены все приостановленные изменения рабочего пространства. В противном случае можно использовать одну из других 11 доступных перегрузок методов и отфильтровать список приостановленных изменений, возвращенных после обращения к TFS.

В следующем примере регистрируются все приостановленные изменения для рабочего пространства:

  1. // В этом примере предполагается, что мы получили ссылку
  2. // на существующее рабочее пространство в предыдущих примерах
  3. var pendingChanges = workspace.GetPendingChanges();
  4. var results = workspace.CheckIn(pendingChanges, "My check in.");

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

В системе управления версиями можно регистрировать не только приостановленные изменения. Также можно регистрировать:

  • Дополнения.
  • Ветви.
  • Удаление/отмену удаления
  • Свойства.
  • Переименования.

Приостановленные изменения также можно отменять, вызывая метод Workspace.Undo. Как и в случае метода CheckIn, вы также должны указать, какие приостановленные изменения необходимо отменить. В следующем примере отменяются все приостановленные изменения для рабочего пространства:

  1. var pendingChanges = workspace.GetPendingChanges();
  2. var results = workspace.Undo(pendingChanges);

Получение журнала

Стандартной задачей при работе с Team Explorer является просмотр журнала доступа к одному или нескольким файлам или папкам. В некоторых случаях может потребоваться программная реализация этой задачи. Как вы наверняка ожидаете, для опроса журнала предусмотрен специальный API-интерфейс. На самом деле, я намерен обсудить метод, доступный в экземпляре VersionControlServer (в предыдущем примере — переменная vcs). Этот метод называется VersionControlServer.QueryHistory, и он имеет восемь возможных перегрузок. Этот метод предоставляет разнообразные возможности опроса сервера управления версиями в зависимости от типов и значений параметров, передаваемых вызову метода.

На рисунке 5 показано, как может выглядеть представление журнала для файла Form1.cs при использовании SCE.

History for Form1.cs

Рисунок 5. Журнал файла Form1.cs

Вы можете написать программный код для поддержки этой функциональности, воспользовавшись примером кода на рисунке 6.

Рисунок 6. Получение журнала элемента

  1. var vcs = _tpc.GetService<VersionControlServer>();
  2. var results = vcs.QueryHistory(
  3. "$/Demo/TFS_VC_API/Form1.cs", // Элемент (файл) для запроса журнала
  4. VersionSpec.Latest,           // Запрос новейшей версии
  5. 0,                            // Параметр Deletion ID нас не интересует
  6. RecursionType.Full,           // Рекурсивный обход всех папок
  7. null,                         // Указываем значение null, чтобы опросить всех пользователей
  8. new ChangesetVersionSpec(1), // Начальная версия — первый набор изменений       
  9.                               // в TFS
  10. VersionSpec.Latest,           // Конечная версия совпадает с новейшей версией
  11.                               // в TFS
  12. int.MaxValue,                 // Максимальное количество возвращаемых записей
  13. true,                         // Включить изменения
  14. false);                     // Слотовый режим
  15. if (results != null)
  16. {
  17.   foreach (var changeset in (IEnumerable<Changeset>)results)
  18.   {
  19.     if (changeset.Changes.Length > 0)
  20.     {
  21.       foreach (var change in changeset.Changes)
  22.       {
  23.         ResultsTextBox.Text +=
  24.           string.Format(" {0}\t{1}\t{2}\t{3}\t{4}\t{5}\r\n",
  25.           change.Item.ChangesetId,
  26.           change.ChangeType,
  27.           changeset.CommitterDisplayName,
  28.           change.Item.CheckinDate,
  29.           change.Item.ServerItem,
  30.           changeset.Comment);
  31.       }
  32.     }
  33.   }
  34. }

Обратите особое внимание на аргумент в строке 13, показанный на рисунке 6. Для параметра includeChanges я указал значение true. Если вы укажете значение false, то отдельные изменения для журнала версий не будут включены в возвращаемые результаты, а в примере на рисунке 6 будут отсутствовать подробные сведения. Базовую версию журнала набора изменений можно отобразить, не возвращая изменения, однако при этом некоторые подробности окажутся недоступными.

Запуск программного кода из примера на рисунке 6 позволяет получить результаты, показанные на рисунке 7.

History from API

Рис. 7. Журнал, полученный с помощью API

Существует множество других вариантов вызова API-интерфейса QueryHistory. Чтобы подробнее изучить возможные варианты использования этого метода, опробуйте различные функции SCE по работе с журналом. Вы можете создавать запросы не только к журналу, но и ко многим другим объектам. Например, VersionControlServer обеспечивает множество других методов, связанных с запросами, среди которых:

  • QueryBranchObjectOwnership,
  • QueryBranchObjects,
  • QueryLabels,
  • QueryMergeRelationships,
  • QueryMerges,
  • QueryMergesExtended,
  • QueryMergesWithDetails,
  • QueryPendingSets,
  • QueryRootBranchObjects,
  • QueryShelvedChanges,
  • QueryShelvesets,
  • QueryWorkspaces.

Сервер управления версиями может предоставить большой объем информации, а различные методы создания запросов служат окном доступа к этой информации.

Дальнейшие действия

Группа Rangers в своих статьях лишь слегка затронула функции управления версиями, реализованные в объектной модели TFS. Описанные в этой статье функции могут оказаться весьма полезными и действенными, однако сервер управления версиями TFS поддерживает великое множество других функций, которых мы еще не касались. Среди примеров этих функций можно выделить создание ветвей и слияние, наборы отложенных изменений, метки и события управления версиями. В этой серии статей мы надеемся рассказать о многих из этих API и поделиться с вами знаниями, которые нужны для максимально полного использования объектной модели TFS. Оставайтесь с нами.