Привет хабр! Основная речь пойдет про разработку на .Net, то есть с использованием Microsoft Visual Studio, ReSharper, Nuget и пр.
Я думаю, многие из вас разрабатывали большие решения (в msdn — solution), со множеством подпроектов. И в этом случае нередко становилась проблема синхронизации Nuget пакетов, настроек сборки и т.д. Причем, ReSharper здесь поможет слабо, разве что он тоже начнет путаться во множестве используемых библиотек.
Чтобы проверять исходный код, было сделано Open Source решение — SolutionCop, которое бесплатно для использования.
Для начала приведу парочку примеров, когда не помешали бы проверки наших решений.

Пример 1: разные версии Nuget библиотек.


Например, есть три проекта: exe, dll1 и dll2. exe ссылается на обе библиотеки, каждая из них ссылается, например, на RX. Но dll1 использует RX 2.2.0, а dll2 — RX 2.2.5. На деле, далеко не сразу можно получить ошибку, так как сигнатуры функций более-менее совпадают, более того, MsBuild чаще всего собирает проекты в одном и то же порядке. Однако подобная конфигурация может привести к проблемам, которые появятся после deployment'а, когда все модульные тесты пройдут (т.к. они ссылаются только на свою библиотеку), и когда будет готовиться результирующий набор файлов.

Пример 2: проект ссылается на библиотеку напрямую, а не через Nuget.


Опять возьмем три наших проекта: exe, dll1 и dll2. Допустим, мы также используем еще Jetbrains.Annotations, чтобы размечать код NotNull/CanBeNull аттрибутами и получать симпатичный статический анализ. Но вот незадача: для dll1 мы честно скачали пакет версии 9.2.0, а в dll2 мы просто попросили ReSharper добавить ссылку, что он и сделал. В итоге, в packages.config файле dll2 нет пакета с аттрибутами, а значит, если проект будет собираться в порядке dll2 --> dll1 --> exe, то мы получим ошибку, ведь Nuget пакет скачается только при сборе dll1!

Можно привести еще ряд примеров, когда разные настройки в проектах могут привести к веселым проблемам. Например, проекты для .Net 4.0 и .Net 4.5 могут ссылаться на одинаковые пакеты, но на разные библиотеки в них (см. Nuget help), а значит мы опять будем получать спецэффекты при сборке проектов. Однако лучше перейдем к SolutionCop.

Установка


SolutionCop доступен на Nuget, устанавливается он на уровень всего решения. После установки пакета необходимо создать xml файл с правилами, настроить их и встроить проверяльщика в процедуру сборки на CI.
Пошагово:
  1. Создаем xml файл с правилами (будем проверять сам SolutionCop):

    SolutionCop.exe -s "C:\git\SolutionCop\src\SolutionCop.sln"

    После этой команды возле sln файла появится файл SolutionCop.xml. В нем перечислены все правила, но все они выключены. Рассмотрим их позже.
  2. Настраиваем CI сервер так, чтобы SolutionCop запускался при каждом билде (решение со 100 проектами проверяется 3-4 секунды). Для TeamCity можно даже публиковать статус с более удобном формате. Для всех остальных — придется читать Error Output. Приложение вернет 0, если все правила выполнились успешно. Итак, командная строка для TeamCity:

    SolutionCop.exe -s "C:\git\SolutionCop\src\SolutionCop.sln" -b TeamCity --suppress-success-status-message.

    Последний аргумент необходим в случае, если TeamCity не пишет статуса модульных тестов (несмотря на то, что они выполнялись позднее). Он отключит вывод SolutionCop для случая, если все правила выполнились.

Правила


Ита��, SolutionCop настроен, он теперь заглядывает в решение, но ничего не проверяет. А потому перечислю правила, которые могут пригодиться. Детальное описание их использование есть на GitHub, я просто перечислю интересности. Для каждого правила, конечно же, можно задавать исключения и пр.
  • WarningLevel. Проверяет, что все проекты имеют Warning Level не ниже заданного.
  • TreatWarningsAsErrors. Смежное с предыдущим. Тоже синхронизует настройку компиляции.
  • TargetFrameworkVersion. Сихнронизует версию .Net для всех проектов
  • SuppressWarnings. Сихнронизует список предупреждений, на которые компилятор будет закрывать глаза.
  • FilesIncludedIntoProject. Проверяет, что все файлы, находящиеся в папке с проектом, включены в этот проект (дополнительно указыватся расширение). Невероятно полезное правило. Например, один раз при неправильном git merge у нас из проекта с модульными тестами выпало около трети файлов. Заметили это, конечно, не сразу, к тому времени мы упустили уже несколько багов. Также помогает с очисткой репозитороя, чтобы избежать кучи висящих файлов, которые никто не использует.
  • ReferenceNuGetPackagesOnly. Запрещает динамически линковаться на библиотеки, которые не добавлены как NuGet пакеты. По факту это исправление примера 2 выше.
  • NuGetPackagesUsage. Определяет Nuget пакеты, которые можно использовать. Эта настройка нужна для задач, когда в продукте есть несколько команд, у каждой свой репозиторий, они ссылаются друг на друга, а также на некоторые общие компоненты. И чтобы избе��ать проблем при объединении кода, можно определить общие правила для всех: какие версии пакетов кому можно использовать. В этом случае все правила хранятся отдельно от кода, в отдельном репозитории.
  • SameNuGetPackageVersions. Запрещает использование разных Nuget пакетов в решении. Исправление ошибки из примера 1.
  • NuGetAutomaticPackagesRestore. Проверяет, что все проекты восстанавливают Nuget пакеты в процессе сборки. Иначе разный порядок компиляции на CI сервере может привести к тому, что nuget пакеты не подгрузятся вовремя, так как какой-то проект пользовался тем, что его зависимости загружают другие проекты.


На деле, в SolutionCop есть и ряд других правил, которые помогут вычищать код. Я постарался перечислить те, которые могут понадобиться почти всем, кто разрабатывает на .Net.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
А как вы автоматически проверяете свой код после коммита?
71.43%Continuous builds45
53.97%Continuous unit tests34
36.51%Continuous integration tests23
36.51%Статические анализаторы кода (например, StyleCop)23
6.35%Валидаторы корректности проекта (т.е. SolutionCop или аналоги)4
7.94%Другое (в комментариях)5
Проголосовали 63 пользователя. Воздержались 44 пользователя.