2014. március havi bejegyzések

TFS work item típusok testreszabása

Az egyik legjobb dolog a TFS-ben, hogy a forráskód változását nem csak a changesetekhez írt kommentek dokumentálják, hanem minden változást feladatokhoz, work itemekhez rendelhetünk. A TFS ad nekünk néhány feladat típust (Bug, Task, Issue, User Story stb.), de persze előfordulhat, hogy ezek nem teljesen elégítik ki az igényeinket és jó lenne módosítani őket.

A work item típusok kezelésére hagyományosan a parancssoros witadmin.exe szolgál, amivel exportálhatjuk a típus definíciókat XML-be, majd módosítás után visszatölthetjük őket a szerverre. A módszer előnyre, hogy a módosított XML-t stílszerűen elmenthetjük a TFS-be 🙂

Aki a grafikus módszereket jobban kedveli, annak érdemes a nem támogatott, ám elég ütős TFS Power Toolst feltelepíteni. Telepítés után megjelenik a Tools menüben egy Process Editor menüpont, amivel megnyithatjuk a work item típus definícióját közvetlenül a szerverről:

vs-open-wit-from-server

Csak ki kell választanunk, hogy melyik projekt melyik típusát akarjuk szerkeszteni:

vs-select-work-item-type

És máris megkapjuk a típushoz tartozó tulajdonságok listáját:

vs-work-item-type-properties

Ha például zavaró, hogy az Assigned To mező mindig megjeleníti a szerver összes felhasználóját, akkor kiválaszthatjuk ezt a mezőt a listából, majd az Edit gombra kattintva módosíthatjuk azt. A felugró szerkesztő ablak második, Rules fülén látható a probléma forrása:

vs-field-definition

A gond a Team Foundation Server Valid Users csoportot jelentő VALIDUSER sor, ami tartalmazza az összes projekt összes felhasználóját. Ezt törölhetjük, és felvehetjük helyette az ALLOWEDVALUES szabályt, ahol felsorolhatjuk a választható elemeket. Praktikus felhasználói csoportot megadni, ahol szerver szintű csoportra [Global]\csoportnév, az aktuális projekt csoportjaira pedig [Project]\csoportnév formában hivatkozhatunk. Például:

vs-field-definition-allowedvalues

A Rule Type ablakban megjelenő lehetőségek teljes dokumentációja megtalálható az MSDN All FIELD XML elements reference oldalán.

Save hatására a módosítások közvetlenül a szerverre mentődnek vissza, de hogy a Studio is érzékelje őket, célszerű egy frissítést kérni a Team Explorer ablakban.

 

Technorati-címkék: ,,
Reklámok

UriFormatException TFS teszt e-mail küldésekor

A Team Foundation Server Administration Console egy igen barátságos alkalmazás. Látszik, hogy a felület tervezésekor végiggondolták a tipikus üzemeltetői feladatokat, ezért lehet például könnyen megváltoztatni a service accountot vagy a szerver URL-jét, ráadásul szinte minden beállítás mellett ott van kéznél egy Test gomb, amivel gyorsan kipróbálhatjuk, hogy jó értéket adtunk-e meg.

Az egyik hasznos funkció, hogy a levelezési beállítások mellett található egy Send Test Email funkció:

tfs-email-settings

Ha rákattintunk, akkor a felugró ablakban meg kell adnunk a teszt levél címzettjének e-mail címét és egy szöveget, ami bekerül a levélbe:

tfs-test-email

Ha szerencsénk van, akkor simán el is megy a levél:

tfs-test-email-success

Azonban előfordulhat, hogy nem sikerül a küldés, hanem az alábbi hibaüzenetet kapjuk:

Unable to connect to the TFS server to test email settings. Url = ‘/_api/_common/TestMailSettings?sendTo=myuser%40example.com&message=Test+email’. Exception = System.UriFormatException: Invalid URI: The format of the URI could not be determined.
   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
   at System.Net.WebRequest.Create(String requestUriString)
   at Microsoft.TeamFoundation.Admin.Console.Models.DlgSendTestMailViewModel.SendEmail()

tfs-test-email-error

Az ember ilyenkor átnézi az e-mail küldés beállításait, csakhogy a hibát jelen esetben nem ott kell keresni. Nyissuk meg a Change URLs ablakot, és ellenőrizzük, hogy a Server URL rovatban a Use localhost opció legyen kiválasztva:

tfs-change-urls

Az e-mail küldéses hiba ugyanis csak akkor jön elő, ha a második opciót választjuk, és localhost helyett a gép nevét adjuk meg a Use: rovatban. Akit érint, a Connecten szavazhat, hátha hamarosan kijavítják.

 

Technorati-címkék: ,

TFS 2005 frissítése 2013-ra adatbázis túrással

A tanszéken van egy régi source control szerverünk, ami Team Foundation Server 2005-t futtat, azt a bizonyos 1.0 verziót. Tekintve, hogy alatta már az operációs rendszer, az SQL Server és a SharePoint is kiöregedett, nem beszélve a hardverről, elhatároztam, hogy megfrissítem, méghozzá a 2013 verzióra. A dolog szépségét az adja, hogy nem lehet egyetlen lépésben 2005-ről 2013-ra frissíteni (ami nem is meglepő, hiszen volt köztük 3 verzió), hanem először 2010-re érdemes, ahonnan lehet 2013-ra:

tfs-2005-2013

A 2005-ről 2010-re frissítés trükkös, mert SQL-t és SharePointot is kell frissíteni, amihez nagy segítség a TFS Setup Support Team blogján található leírás és best practice gyűjtemény. A WSS 2.0-3.0 frissítéshez szintén van egy hasznos blog bejegyzés a TFS csapat blogjában.

A TFS frissítése elméletileg egy viszonylag egyszerű folyamat: el kell távolítani az előző verziót, de meg kell hagyni az adatbázisokat az SQL Serverben, majd fel kell telepíteni az új verziót, és a telepítő varázsló Upgrade opciójával csatlakozni kell a régi adatbázishoz, amit a telepítő meg fog frissíteni. Elméletben tényleg nem tűnik bonyolultnak, ráadásul Tim Elhajj Upgrade Team Foundation Server 2012: The Ultimate Upgrade Guide című 61 oldalas step-by-step képeskönyve is sokat segít.

A gyakorlat azonban kicsit más.

Kezdjük ott, hogy sajnos egyik leírásban sincs benne, hogy a TFS 2010 upgrade folyamatban van egy hiba, ami inkonzisztenciát okozhat az adatbázisban, ezért némileg trükközni kell a frissítés során. Erről Brian Harry TFS 2010 Upgrade Issue című cikkében olvashatunk, ahol a hotfix is megtalálható.

Ami azonban még zavaróbb, hogy a simán lefutó frissítés után nem sikerült csatlakoznom a szerverhez, amiről a különböző kliensek nagyon változatos hibaüzenetekkel tájékoztattak, például:

TF400324: Team Foundation services are not available from server MyServer\MyCollection. Technical information (for administrator): Unable to connect to the remote server.

Vagy:

TF205020: A connection could not be made to the following server: MyServer\MyCollection. This server was used during your most recent session, but it might be offline, or network problems might be preventing the connection. Contact the administrator for Team Foundation Server to confirm that the server is available on the network.

Vagy egyszerűen csak:

TF31002: Unable to connect to this Team Foundation Server

A csúcs az volt, amikor a szerveren futó Team System Web Access elérte az adatokat, de a távoli Visual Studio kliens nem tudott csatlakozni, pedig a Network Monitor szerint ment a forgalom szépen, csak épp HTTP 4xx és 5xx hibák jöttek a szerverről (ez egyébként az IIS logban is látszik). Volt olyan is, hogy sikerült csatlakozni a collectionhöz, a work itemeket sikerült is elérni, de a source controlban lévő fájlokat és azok történetét nem.

A különösen érdekes az volt a dologban, hogy a cél szerveren létrehozott új collectiont tökéletesen elérték a kliensek, tehát nem a rendszer szintű beállításokkal (pl. port, tűzfal, tanúsítvány) volt gond, hanem a frissített adatbázisban nem stimmelt valami. Lefuttattam a TFS 2013 Power Toys-ban lévő Best Practices Analyzert, de nem talált semmit sem szerver, sem collection szinten.

Mivel kifogytam az ötletekből, elővettem az SQL adatbázist közvetlenül. Néztem a forgalmat Profilerrel, illetve belenéztem a táblákba Management Studioval, és összehasonlítottam a frissen létrehozott, működő collection adatbázisát a nem működő, frissített adatbázis tartalmával. Így leltem rá a tbl_ServiceDefinition táblára, amiről ugyan dokumentációt nem találtam, de ránézésre a TFS webszolgáltatásaihoz tartozó .ASMX URL végpontokat tartalmazza. Érdekes módon míg az új adatbázisban többnyire minden cella ki volt töltve, addig a frissített adatbázisban a sorok jelentős részében a RelativePath mező értéke NULL volt. Vettem egy nagy levegőt, készítettem egy snapshotot a virtuális gépről, és megfrissítettem a tbl_ServiceDefinition tábla RelativeToSetting, RelativePath és IsSingleton oszlopait azokban a sorokban, ahol a RelativePath NULL volt, és az Identifier oszlopban lévő GUID alapján találtam egyező sort a működő adatbázisban. Íme a végeredmény:

tfs-service-definitions

A klienseken kitöröltem a Visual Studio Team Explorer cache mappát (C:\Users\felhasználónév\AppData\Local\Microsoft\Team Foundation), újra felvettem a szervert, ééééééééééés működött!

Hozzá kell tennem, hogy ez semmilyen szempontból nem jó módszer, nem támogatott és nem is javasolt. Aki hasonlóval küzd, valószínűleg sokkal jobban jár, ha a Microsoft hivatalos terméktámogatásához fordul!

Ezzel együtt ezek után már nem is volt annyira vészes a Configure Features varázsló és a process template-ek manuális frissítése.

 

Távoli asztal jelszó megjegyzése

Igen bosszantó, hogy a remote desktop kliens egyes esetekben csak a felhasználónevet hajlandó megjegyezni, a jelszót nem, mert:

Your credentials did not work

Your system administrator does not allow the use of saved credentials to log on to the remote computer COMPUTER because its identity is not fully verified. Please enter new credentials.

rdp-credentials

Ezen úgy lehet segíteni, ha megnyitjuk a Local Group Policy Editort (gpedit.msc), majd elnavigálunk ehhez az ághoz: Computer Configuration –> Administrative Templates –> System –> Credentials Delegation. Itt az Allow delegating saved credentials with NTLM-only server authentication opciót kell Enabled értékre állítani.

Az Add servers to the list opció melletti Show… gombra kattintva felvehetjük azokat a gépeket, amelyekre ezt alkalmazni szeretnénk, mégpedig TERMSRV/gépnév formában, sőt akár minden gépre is hivatkozhatunk a TERMSRV/* érték megadásával.

 

Technorati-címkék: ,

Exception calling "SqlBackup" with "1" argument(s)

Az egyik szerverünkön az alábbi PowerShell script végzi az SQL Server adatbázisok mentését:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null

$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") $dbInstance
$backup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
$backup.Action = "Database"
$backup.BackupSetDescription = "Full backup of " + $dbName
$backup.BackupSetName = $dbName + " backup"
$backup.Database = $dbName
$backup.MediaDescription = "Disk"
$backup.Devices.AddDevice("$localSqlBackupPath", "File")
$backup.SqlBackup($server)

Ez a kód most már évek óta működik rendesen, szépen készülnek a backupok naponta. Ám az utóbbi időben érdekesen kezdett viselkedni a szkript: egyes adatbázisokat mindig lementett, másokat pedig – amikkel korábban nem volt gond – többnyire nem. A naplóba az alábbi hibaüzenet került:

Exception calling "SqlBackup" with "1" argument(s): 
"Backup failed for Server 'MyServer\MySqlInstance'. " At D:\Backups\BackupSite.ps1:151 char:22 + $backup.SqlBackup <<<< ($server) + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : DotNetMethodException

Nehezen derült ki, hogy a hibának semmi köze a függvény meghívásának módjához, hanem a problémát az okozza, hogy megnőtt az adatbázis, és az SqlBackup függvény 10 perc után timeoutolódik. A ServerConnection objektum StatementTimeout tulajdonságával lehet kikapcsolni az időtúllépés figyelését:

$server.ConnectionContext.StatementTimeout = 0

 

Technorati-címkék: ,

Fájlok csoportosítása a Solution Explorer ablakban

A Visual Studio Web Essentials egyik praktikus szolgáltatása, hogy képes bizonyos fájlok feldolgozására azonnal, amint mentjük őket. Például képes a TypeScript fájlokat mentéskor azonnal lefordítani JavaScript fájlra, sőt még a map fájlt is előállítja hozzá. Vagy képes a LESS fájlokból mentéskor legenerálni a CSS fájlt normál és minimalizált változatban is.

Ez a szolgáltatás nagyon hasznos, ha ez a fajta feldolgozás nem része a build folyamatunknak, és ebben az esetben teljesen logikus, hogy az így létrejövő output fájlok a projekt fájlhoz is hozzáadódnak.Az már kevésbé szerencsés, hogy az eredeti és a generált fájlok közötti kapcsolatot a Visual Studio nem mindig veszi észre, és nem is mutatja a Solution Explorer ablakban. Szerencsére ha vesszük a bátorságot és beleszerkesztünk a .csproj fájlba, akkor rávehetjük a Solution Explorer ablakot, hogy egymás alá hierarchiába rendezze az egymáshoz kapcsolódó fájlokat. A trükk a DependentUpon elem használata, például:

<TypeScriptCompile Include="js\Main.ts" />
...
<Content Include="js\Main.js">
    <DependentUpon>Main.ts</DependentUpon>
</Content>
<Content Include="js\Main.js.map">
    <DependentUpon>Main.ts</DependentUpon>
</Content>

Íme az eredmény:

solution-explorer-group-ts

Sőt, akár több szint mélyre is mehetünk:

<None Include="css\default.less" /> 
... 
<Content Include="css\default.css"> 
    <DependentUpon>default.less</DependentUpon> 
</Content> 
<Content Include="css\default.min.css"> 
    <DependentUpon>default.css</DependentUpon> 
</Content>

Ebből pedig ez lesz:

solution-explorer-group-less

 

Technorati-címkék:

MVC nézetek fordítása hibamentesen

A Visual Studio és az ASP.NET alapértelmezés szerint nem fordítási időben, hanem futási időben dolgozza fel a MVC nézetekben lévő kódot. Ennek természetesen az az eredménye, hogy ha ott valamilyen hibát vétünk, akkor az csak futási időben fog kiderülni.

Szerencsére van arra lehetőség, hogy rávegyük a Studiot, fordítsa le a nézeteket is a build folyamat részeként. Ehhez nyissuk meg az MVC projekthez tartozó projekt fájlt (.csproj), és írjuk át az MvcBuildViews elem értékét false-ról true-ra:

<MvcBuildViews>true</MvcBuildViews>

Ez meg is oldja a kezdeti problémát, ám gyakran bevezet egy újabbat. Időnként fordításkor vagy a webalkalmazás publikálásakor az alábbi hibaüzenetet kaphatjuk:

It is an error to use a section registered as allowDefinition=’MachineToApplication’ beyond application level.  This error can be caused by a virtual directory not being configured as an application in IIS.

A legborzasztóbb ebben az üzenetben, hogy nem csak az nem derül ki belőle, hogy hol a hiba, hanem az sem, hogy hogyan lehet kijavítani.

A megoldás az obj mappa törlése fordítás előtt, és a hibaüzenet máris megszűnik. Gondoltad volna a hibaüzenet alapján?

Aki nem szeretné mindig kézzel törölgetni ezt a mappát, az persze megteheti a build folyamat első lépéseként is. Szerencsére az MSBuild ad nekünk egy BaseIntermediateOutputPath nevű változót, ami pont az obj mappára mutat, sőt még egy RemoveDir nevű task is van hozzá, így már csak össze kell pakolni őket. Megint nyissuk meg a .csproj fájlt, és vegyünk fel egy RemoveDir elemet a BeforeBuild target-hez:

<Target Name="BeforeBuild">
    <RemoveDir Directories="$(BaseIntermediateOutputPath)" />
</Target>

Akinek esetleg a bin mappával van személyes nézeteltérése, az esetleg használhatja a BaseOutputPath változót.

 

Technorati-címkék: ,,