سؤال

نحن نستخدم ملف T4 لإدارة إصدار التجميع الخاص بنا ؛ في الأساس نحن نتابع هذه الإجراءات لتجديد نسخ التجميع لدينا على كل بناء. يتم ذلك عن طريق وجود .csproj استخدم نمذجة SDK لعام 2013 بغرض تخصيص تكوين تجديد T4 مع MSBuild.

هذا يعمل بشكل رائع! لسوء الحظ ، لا يبدو أن بناء فريق Foundation لخدمة Team Foundation يدعم توليد رمز T4 في وقت الإنشاء لأن مثيلات VS 12 على خادم Build لا تحتوي على texttemplating.targets في موقع التثبيت الافتراضي ؛ من المفترض أن النمذجة/VS SDKs غير مثبتة على خادم الإنشاء (من سجلات فشل بناء TFSERVICE):

لم يتم العثور على المشروع المستورد "C: Program Files (x86) msbuild 12.0 Microsoft VisualStudio V12.0 texttemplating microsoft.texttemplating.targets". تأكد من أن المسار في الإعلان صحيح ، وأن الملف موجود على القرص.

هل هناك خطط لتثبيت Addons VS 2013 التي تم إصدارها Microsoft (VS SDK ، نمذجة SDK ، إلخ) على صورة خادم البناء؟

هل هناك عمل يمكنني تنفيذه بحيث عندما ألتزم بخدمة مؤسسة Team Code عبر GIT ، لن ينكسر البناء؟

كيف يمكنني تكوين وحدة تحكم بناء TFSERVICE المستضافة لتحويل ملفات T4 الخاصة بي أثناء بناءها؟

هل كانت مفيدة؟

المحلول

انتهى بي الأمر بإنشاء حل مختلف لمهمة وجود خادم البناء التلقائي للتجميعات لدينا. بدلاً من استخدام T4 لإنشاء ملف AssemblyInfo.cs ديناميكيًا للمشاركة عبر رابط العنصر إلى مشاريع أخرى ضمن الحل (وبالتالي يتعين عليهم التعامل مع إزعاج معرفة كيفية الحفاظ على تجديد الملف الحالي لهذا الغرض) ، أنا تجنب T4 تماما. لقد كان الكثير من العمل يتكامل مع آلة الإنشاء عن بُعد الطرف الثالث ، وإدارة الإضافات و SDKs التي تسمح بمعالجة T4 وما إلى ذلك. هناك حل أبسط بكثير يتضمن MSBUILD المهام المجتمع التي وجدتها من هذا السؤال جدا. الحل بسيط بأناقة مقارنة بـ T4! إليكم كيف تهتز:

في كل مرة تم تصميم هذا المشروع ، Application.version.csproj ، مهام MSBuild المحددة في مكتبة "MSBuildCommunity" التي تم تثبيتها في الطرف الثالث. AssemblyFileversion, AssemblyInformationalversion, التجميع استنادًا إلى وقت تاريخ UTC الحالي وإدخاله في ملف جديد ، Autoversion.cs ، الموجود في دليل "خصائص" هذا المشروع (إلى جانب ملف AssemblyInfo.cs). لدى AssemblyInfo.cs سمات التجميع هذه إلى الأبد لتجنب أخطاء بناء سمات التجميع المحددة المعرفة). بعد توليد Autoversion.cs (الذي يحدث قبل الإنشاء) ، يدمج المترجم سمات إصدار التجميع المذكورة أعلاه في التجميع المبني. يعكس هذا الإصدار وقت UTC الذي تم بناؤه (انظر أدناه).

كل .csproj الأخرى في .sln تشترك في إصدار إصدار التجميع الديناميكي هذا ، وهو إنشاء رابط ملف إلى ملف Autoversion.cs الذي تم إنشاؤه. يجب أن تكون هذه التجميعات لديها أيضًا تجميعها. يتم إصدار إصدار التجميع لجميع المشتركين .csprojs في .sln في كل مرة تم تصميم myapplication.csproj (أو إعادة بنائها). إليك .csproj لمشروع الإصدار:

  <!-- START DYNAMIC ASSEMBLY VERSIONING WORK-->
  <!--MSBuild Community Tasks path as installed via the nuget package 'Install-Package MSBuildTasks'-->

 <PropertyGroup>
    <MSBuildCommunityTasksPath>$(MSBuildThisFileDirectory)..\.build</MSBuildCommunityTasksPath>
    <My-PropertiesDir>Properties</My-PropertiesDir>
  </PropertyGroup>
  <PropertyGroup>

   <!--this should only be incremented (starting at zero) for MAJOR application releases this should never be reset only incremented!--> 
    <ManualMajorVersion>0</ManualMajorVersion>

   <!--3 digits maximum should only be manually incremented (starting at zero) for feature releases-->
   <!--!this should be reset to '0' at the start of each caldenar Year-->  
    <ManualMinorVersion>0</ManualMinorVersion>
  </PropertyGroup>

   <!--Import MSBuild Community Tasks library installed from Nuget -->
   <!--This library contains defined MSBUILD tasks useful for dynamically generating Assembly information via MSBUILD https://github.com/loresoft/msbuildtasks--> 
  <Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets" />
  <Target Name="BeforeBuild">
    <Time Format="yy.MM.dd.HHmm" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="My-VersionNumber" />
    </Time>
    <Message Text="Auto versioning from UTC time: $(My-VersionNumber) ...">
    </Message>
    <Time Format="yy" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Year" />
    </Time>
    <Time Format="MM" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Month" />
    </Time>
    <Time Format="dd" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Day" />
    </Time>
    <Time Format="HH" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Hour" />
    </Time>
    <Time Format="mm" Kind="Utc">
      <Output TaskParameter="FormattedTime" PropertyName="Minute" />
    </Time>
    <ItemGroup>
      <My-AssemblyInfo Include="$(My-PropertiesDir)\AutoVersion.cs" />
      <Compile Include="@(My-AssemblyInfo)" />
    </ItemGroup>
    <MakeDir Directories="$(My-PropertiesDir)" />
    <PropertyGroup>
      <GeneratedAssemblyVersion>$(ManualMajorVersion).$(Year)$(ManualMinorVersion).$(Month)$(Day).$(Hour)$(Minute)</GeneratedAssemblyVersion>
    </PropertyGroup>
    <AssemblyInfo OutputFile="@(My-AssemblyInfo)" CodeLanguage="CS" AssemblyFileVersion="$(GeneratedAssemblyVersion)" AssemblyInformationalVersion="$(GeneratedAssemblyVersion)" AssemblyVersion="$(GeneratedAssemblyVersion)" Condition="$(GeneratedAssemblyVersion) != '' " />
  </Target>
  <!-- END DYNAMIC ASSEMBLY VERSIONING WORK-->

وكذلك اختبار الوحدة للتحقق من نفسك:

/// <summary> A test to validate the configured, auto-generated assembly versioning is working as expected </summary>
[Test]
public void AssemblyVersioningTest()
{
    DirectoryInfo currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
    DirectoryInfo versioningDir = new DirectoryInfo(currentDirectory.FullName + "\\" + VERSIONING_DYNAMIC_FILE_DIRECTORY);

    // verify versioning directory located/loaded/exists
    Assert.IsTrue(versioningDir.Exists);

    // locate the VERSIONING_DYNAMIC_FILE file within the VERSIONING_DYNAMIC_FILE_DIRECTORY directory
    string dynamicFilePath = versioningDir.FullName + "\\" + VERSIONING_DYNAMIC_FILE;

    // get the FileInfo for the file that is used to dynamically generate assembly versioning
    FileInfo dynamicVersioningFileInfo = new FileInfo(dynamicFilePath);
    Assert.IsTrue(dynamicVersioningFileInfo.Exists);

    // get the two digit creation Dates/Times for the assembly's file as strings
    // since that's what the versioning reflects
    DateTime dynamicVersioningFileLastWriteTime = dynamicVersioningFileInfo.LastWriteTime;

    #region    Created VERSIONING_DYNAMIC_FILE
    string dynamicVersioningFileLastWriteTimeYear = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("yy");

    string dynamicVersioningFileLastWriteTimeMonth = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("MM");
    string dynamicVersioningFileLastWriteTimeDay = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("dd");

    string dynamicVersioningFileLastWriteTimeHour = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("HH");
    string dynamicVersioningFileLastWriteTimeMinute = dynamicVersioningFileLastWriteTime.ToUniversalTime().ToString("mm");
    #endregion Created VERSIONING_DYNAMIC_FILE

    // get *this* assembly from the .sln using reflection since this assembly consumes/is dependent upon the versioning functionality we
    // are testing
    Assembly theAssemblyExecutingThisTest = Assembly.GetExecutingAssembly();

    // get this assembly's version
    // we will investigate this to compare it to a reverse-engineering of what we would
    // expect it to be based 
    AssemblyName testingAssemblyName = theAssemblyExecutingThisTest.GetName();
    Version testingAssemblyVersion = testingAssemblyName.Version;

    #region    Generated Assembly Versioning
    // get the first two digits of the assemblyVersion.MinorVersion - these represent the year
    string testingAssemblyVersionMinorYear = testingAssemblyVersion.Minor.ToString().Substring(0, 2);
    // the rest of the digits represent the manually-configured version and can be 1-3 chars long
    string testingAssemblyVersionMinorManual = GetMinorManualFromVersionString(testingAssemblyVersion.Minor.ToString());

    string testingAssemblyVersionBuildMonth = testingAssemblyVersion.Build.ToString("D4").Substring(0, 2);
    string testingAssemblyVersionBuildDay = testingAssemblyVersion.Build.ToString("D4").Substring(2, 2);

    string testingAssemblyVersionRevisionHour = testingAssemblyVersion.Revision.ToString("D4").Substring(0, 2);
    string testingAssemblyVersionRevisionMinute = testingAssemblyVersion.Revision.ToString("D4").Substring(2, 2);
    #endregion Generated Assembly Versioning

    // verify the assembly's minor version: last two digits match of assembly file creation year
    // (pad minorversion 4 spaces in case released minor version is empty)
    Assert.AreEqual(dynamicVersioningFileLastWriteTimeYear,
        testingAssemblyVersionMinorYear,
        "Assembly's minor version: last two digits do not match assembly file last write time year");

    // verify the assembly's minor version is comprised of two digit 'released minor version' + two digit year of assembly file creation date
    Assert.AreEqual(dynamicVersioningFileLastWriteTimeYear + testingAssemblyVersionMinorManual,
        testingAssemblyVersionMinorYear + testingAssemblyVersionMinorManual,
        "Assembly's minor version: not comprised of two digit year of assembly file last write time date + dynamically-sized 'minor manual version' + ");

    // verify the Assembly's build version is comprised of two digit month + two digit day of assembly file creation date
    Assert.AreEqual(dynamicVersioningFileLastWriteTimeMonth + dynamicVersioningFileLastWriteTimeDay,
        testingAssemblyVersionBuildMonth + testingAssemblyVersionBuildDay,
        "Assembly's build version: not comprised of two digit month + two digit day of assembly file last write time date");

    // verify the Assembly's revision version is comprised two digit hour + two digit minute of assembly file creation date
    Assert.AreEqual(dynamicVersioningFileLastWriteTimeHour + dynamicVersioningFileLastWriteTimeMinute,
        testingAssemblyVersionRevisionHour + testingAssemblyVersionRevisionMinute,
        "Assembly's revision version: comprised two digit hour + two digit minute of assembly file last write time date");
}

نصائح أخرى

قمنا بحل مشكلة مماثلة من خلال تضمين ملفات V&M SDK (Microsoft.TextTemplating.build.tasks.dll ، microsoft.texttemplating.targets ، microsoft.visualstudio.texttemplating.sdk.host.1x.0.dll) مراقبة.

IMO هذه هي الطريقة الحقيقية الوحيدة لإدارة SDKs من طرف ثالث في مشاريع كبيرة: التثبيت على كل آلة Dev والبناء فردية هشة للغاية بحيث لا يمكن أن تكون عملية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top