Pull to refresh

Comments 3

То, о чем вы пишете, называется ScriptDom и оно входит в поставку DacFx, но самим DacFx не является. Более того, недавно парсер выделен в самостоятельный нугет и теперь его в решения по анализу кода TSQL можно без всех остальных составляющих пакета DacFx затягивать. Объектная модель описана довольно хорошо, вот корректная ссылка на доки.

ScriptDom сам построен на ANTLR, потому противопоставлять их не совсем корректно, хоть мысль и понятна.

SqlCodeAnalysusRule мы не используем, запилили свой линтер "сбоку" в виде экстеншена к студии. В SSDT крайне неудачно реализована работа с code-analyzer'ами, по сравнению с Roselyn тут всё находится на чудовищно допотопном уровне. В частности, согласно официальным докам, скомпилированный аналайзер нужно подсовывать в правильное место в Program Files, что в корпоративном мире (без админских прав на компе) не всегда возможно в принципе. Если для кого актуально, я заводил фича-реквест для разрабатываемого нового SDK/SSDT/не важно куда они это смогут вкорячить, чтобы сделали поддержку аналайзеров как нугетов безо всяких магических путей в Program Files - накиньте лайков.

Вы подняли очень больную тему. И правда, Microsoft создала прекрасный инструмент для проверки кода, но тот способ, которым они предлагают распространять библиотеку, абсолютно не приемлем. Первое что приходит на ум — анализатор Roslyn. Этот пример нас очень вдохновил, и мы решили попробовать поступить схожим образом. Давайте попробуем разобраться вместе.

Библиотека с нашими правилами проверки ищется в той же папке (C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\150), где лежит библиотека Microsoft.Data.Tools.Schema.Tasks.Sql.dll. В документации предлагают подкладывать наш dll в эту папку. Но, как вы сказали, это сильно не удобно. Если посмотреть C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Microsoft\VisualStudio\v16.0\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets, то можно обнаружить, откуда берётся задание SqlStaticCodeAnalysisTask:

  <UsingTask TaskName="SqlStaticCodeAnalysisTask" AssemblyFile="$(SqlServerRedistPath)\Microsoft.Data.Tools.Schema.Tasks.Sql.dll" />

Параметр $(SqlServerRedistPath) задается несколькими строками выше (через параметр $(SSDTPath)):

  <PropertyGroup>

    <ReferencePath Condition="$(SSDTPath) != ''">$(ReferencePath);$(SSDTPath)</ReferencePath>

    <DacPacRootPath>$(VsIdePath)</DacPacRootPath>

    <SqlServerRedistPath Condition="'$(SSDTPath)' != ''">$(SSDTPath)</SqlServerRedistPath>

    <SqlServerRedistPath Condition="'$(SqlServerRedistPath)' == ''">$(VsIdePath)\Extensions\Microsoft\SQLDB\Dac\150</SqlServerRedistPath>

  </PropertyGroup>

Соответственно параметр $(SSDTPath) можно указать прямо в sqlproj.

Возвращаясь к анализатору Roslyn: он представляет из себя NuGet-пакет. Что нам мешает сделать то же самое? Создадим NuGet-пакет, в котором будут все dll из папки C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\150 + библиотека с нашими проверками. После того, как опубликовали библиотеку, необходимо руками добавить наименование этого пакета в sqlproj (VS не поддерживает NuGet в проектах sql). Для этого в проект добавляем несколько строк:

<ItemGroup>

  <PackageReference Include="OurCompany.OurValidations" Version="1.13.0" GeneratePathProperty="true">

    <PrivateAssets>all</PrivateAssets>

    <IncludeAssets>build</IncludeAssets>

  </PackageReference>

</ItemGroup>

Присваиваем значения для параметра $(SSDTPath):

<PropertyGroup>

  <SSDTPath>$(PkgOurCompany_OurValidations)\lib\net472</SSDTPath>

</PropertyGroup>

Изначально восстанавливаем NuGet-пакет:

msbuil MyProjectName.sqlproj /t:Restore

Собираем проект:

msbuil MyProjectName.sqlproj /t:Build

Правда, такое решение работает только при построении из консоли, так как Visual Studio, насколько я понимаю, смотрит на оригинальные dll. Но нам ничего не мешает добавить Target, который будет вызывать MSBuildTask c Target=StaticCodeAnalys.

Уже сейчас в [SDK-Style](https://github.com/microsoft/DacFx/blob/main/src/Microsoft.Build.Sql/sdk/Sdk.targets#L51) проекте можно обнаружить, что БД [master](https://www.nuget.org/packages/Microsoft.SqlServer.Dacpacs.Master) подтягивается из NuGet. 

Что касается Extension в Visual Studio: действительно, таким способом распространять правила проверки куда удобнее. Но а как вы проверите код при сборке в CI (continuous integration)?

Экстеншен к студии - это для локальной работы, для CI сделан CLI-инструмент, он же доступен желающим для использования в качестве External Tools в VS неподдерживаемой версии или в SSMS, SourceTree. CLI сделать проще, чем Extension, с него и начинали. За основу брали OpenSource проект tsqllint и двигались от плагина для него к полностью своему решению с ~300 правилами. В упомянутом проекте, к слову, можно найти хорошие примеры работы со ScriptDom.

С нугетами работать было бы здорово, если бы инструкция к тому, как заставить это работать хотя бы в некоторых случаях не занимала целый экран. Новый Microsoft.Build.Sql SDK находится в зачаточном состоянии, пакет носит статус Preview и нормальная поддержка нугетов все еще где-то в далекой (судя по невысокой активности разработчиков) перспективе. Системные БД они действительно как нугеты опубликовали, но воспользоваться ими смогут только те, у кого COLLATION во всех зависимых проектах - English. Для всех остальных эти нугеты бесполезны, дакпаками из них воспользоваться не получится.

Возвращаюсь к решению по обеспечению контроля за кодом. На стороне CI сделать можно по-всякому и там интеграция с VS или другой IDE, очевидно, не нужна, контроль за тем, что анализ будет выполнен, не нужен - все шаги прописаны явно. А на стороне разработчика у нас все равно толком ничего не работает, т.к. пока он явно из CLI не повыполняет все инструкции, цель достигнута не будет (согласен с тем, что и экстешен он должен ставить сам, сам им пользоваться, но я как раз и обращаю внимание на то, что нет никакой разницы в том, чтобы подстраиваться под замороченные условности аналайзера или разрабатывать в относительно свободном стиле, не привязываться к чему-то полуживому). Кроме того, из-за низкого уровня проработанности SDK/SSDT, как описано выше, в абсолютно все sqlproj придется внести пачку изменений, которые могут там появиться только при ручном редактировании sqlproj-файла или при генерации проекта через boilerplate-утилиту, но в любом случае работать с этим очень неудобно. Далее, если продолжать рассуждать о контроле за кодом, то результат анализа мы отправляем в SonarQube, которому нужен особый json-формат. MSBuild, очевидно, умеет только в текстовый лог, что снова не добавляет удобства, путь через подстраивание под предлагаемый механизм анализаторов ничем не помогает в достижении конечной цели.

И стоит ли оно того в итоге? Аналайзер, оформленный по всем правилам SSDT интересен именно как путь высокой интегрированности с процессом разработки и сборки, а эта цель не достигается даже танцами с бубном. Еще Microsoft.SqlServer.Dac.CodeAnalysis дает доступ ко всей модели проекта в объектном виде, можно (предполагаю, т.к. сюда не добрался в экспериментах) бродить по зависимостям, что очень здорово, но всё вышеперечисленное отбивает всякое желание прорубаться через эти джунгли. В очередной раз потрачу время на заход через Microsoft.SqlServer.Dac.CodeAnalysis я уж точно не раньше, чем будет доведен до продуктового состояния Microsoft.Build.Sql. И совсем будет здорово, если там однажды появятся аналоги CodeFix.

Sign up to leave a comment.