‫تجاربی از CI و Automatic Unit Testing با TeamCity

به سلامتی TeamCity را به قصد راه اندازی CI و انجام خودکار Unit Testها راه انداختیم اما مشکلات و مسائل زیادی به وجود آمد. بعضی‌ها حل شدند و بعضی‌ها نه. خلاصه‌ای از نکاتی که به آن برخورد کردم:

۱- نصب خود TeamCity خیلی ساده و سریع بود. ولی تا آنجا که فهمیدم فقط با MSBuild می‌شود با آن کار کرد و مثل TFS نیست که بشود با WorkFlow آن کارهای اضافی کرد.

۲- با آن که از git استفاده می‌کنیم ولی خوشبختانه مسائل ارتباط با git خیلی خیلی کمتر از آنی بود که فکر می‌کردم. حتی بخش CI که بایستی با push کردن هر تغییر تریگر شود بدون کمترین مشکلی کار کرد (اقلاً مشکل خاصی حس نکردم).

۳- معرفی Build Agentها به دلایلی مثل روشن بودن فایروال، نبودن git در مسیر اجرایی ویندوز و غیره اذیت کرد ولی نه خیلی.

۴- مشکل NuGet فوق‌العاده شدید بود. به راحتی آب خوردن یکی دو روز از وقتم را گرفت. با آن که تنظیم کرده بودم که دریافت packageها خودکار باشد ولی TeamCity با آن که packageها را دریافت می‌کرد باز هم build error می‌داد. به عنوان یک راه حل موقتی فایل‌های packageها را دستی در Build Agentها کپی کردم. ولی بعد از کش و قوس‌های فراوان تصمیم گرفتم NuGet را کنار بگذارم و همه Assemblyها مورد نیاز در داخل سورس کنترل اضافه کنم.

۵- مشکل بعدی مربوط به build target در یکی از Agentها بود. اول فکر کردم مشکل به خاطر نصب نبودن MVC 3 (پروژه مورد استفاده ما MVC 3 است) در agent است. اما متوجه شدم آنجام MVC 3 نصب هست و احتمالا مشکل از نصب نبودن Visual Studio 2010 در آنجا است. به هر صورت تصمیم گرفتم کمی کثیف کاری کنم (راه بهتری پیدا نکردم) و فایل ‎.targets مربوطه به agent مشکل دار کپی کنم.

۶- قدم بعدی انجام اتوماتیک Unit Testها بود. تنظیم آن محدود به یک Build Step ساده بود ولی در اولین قدم معرفی اسمبلی حاوی test کمی مشکل ایجاد کرد که با کمی سعی و خطا حل شد. اگر ساختار فولدر پروژه عوض شود باید آن را هم به روز رسانی کنم.

۷- مشکل Unit Test محدود به مشکل قبلی نبود. در یکی Agentها که ۶۴ بیتی بود، Unit Testها Run نمی‌شدند. در Unit Testهای مورد اشاره، عملیات دیتابیسی با استفاده دیتابیس داخل حافظه‌ای SQLite تست می‌شد. یادم آمد که SQLite دو نسخه مجزا برای محیط‌های ۳۲ بیتی و ۶۴ بیتی دارد. باید راهی پیدا می‌کردم تا Testها هم در ماشین ۳۲ بیتی اجرا شوند و هم در ماشین ۶۴ بیتی. تازه ماشین‌های development هم همگی ۳۲ بیت بودند و نباید یکپارچگی را از دست می‌دادم. مناسب‌ترین راه حل این بود که در زمان اجرا (Run Time) تشخیص می‌دادم که محیط ۳۲ یا ۶۴ بیتی است و بعد اسمبلی متناظر را به application اضافه می‌کردم. این راه زیادی Low Level بود. یک راه دیگر استفاده از GAC بود. اما من نهایتاً یک راه ساده و کثیف را (اقلا موقتی) انتخاب کردم. نسخه ۶۴ بیتی SQLite را دستی در فولدر Work (مسیر خاص پروژه من) کپی کردم و مشکل حل شد. حالا کل سیستم ۳۲ بیت بود ولی آن Agent خاص برای انجام Unit Testها از نسخه ۶۴ بیت خودش استفاده می‌کرد.

Customizing build process in TFS 2010

If you ever has need to customize build process in Team Foundation Build 2010, you may noticed that there is several ways to do it while each way is suitable for a specific range of requirements:

1. Running external tools like batch files or ftp.exe or MSBuild Community Tasks via InvokeProcess or via MSBuild Activity.

2. Invoke .Net classes and methods like System.IO.File.Delete() via InvokeMethod.

3. Creating your own custom workflow activity for TFS Build 2010.

For our specific need that is synchronizing a remote server via FTP, none of first 2 ways is suitable. In first way, running external programs, this is very hard to synchronize a whole remote directory and its sub-directories just via ftp.exe and a bunch of batch file commands like FOR. In addition, this may impose dependency to external tools in the server.

In the second way, running .Net classes and methods, we have to create our own ftp utility or use third party tools like ftp.exe or MSBuild Community Tasks. In addition this causes using intensive usage of TF Build activities that’s not easy to copy to new Team Foundation builds in new projects.

Third and last way, creating your own activity is harder to implement but has many advantages over other ways including:

1. High flexibility because this is entirely written by yourself.

2. Maintaining is easier because all of your work is kept in a single Visual Studio project.

3. It is easier to deploy it in new team builds because it is simply just one single workflow activity.

4. It is easier to configure. You configure it via its arguments and variables. No need to modify template process itself.

Continuous Integration with TFS

It’s a few months that I am dealing with continuous integration, automatic builds, TFS and Team Foundation Build deeply. Experiences during this period learned me some points that I’m glad to share with all:

1. Don’t assume anything about build agent. Specifically don’t assume any library is installed on the agent, any assembly registered in build agent’s GAC, any specific file/folder structure exists in build agent, etc. Otherwise you may encounter build breaks in other agents or at another time. Best practices here is to assume that build agent has just .Net framework installed on it and nothing more.

2. Always add assembly references from source control maintained dlls in same project and just as relative path not as absolute path. Otherwise you may encounter build breaks.

3. Never ever let anyone direct access to live machine that is dedicated to install continuous integration results instantly, specifically for web application projects. Because someone may manually add/modify a file/folder in the web application path. So you may end with a software that needs manual modifications that are never documented nor automated.

4. Automate database creation. Either via maintaining database creation scripts in source control or with help of ORM’s database auto generating feature.