miércoles, 21 de noviembre de 2018

Cómo excluir carpeta Packages de TFS


Es una buena práctica, cuando estamos desarrollando proyectos en Visual Studio y utilizamos paquetes NuGet pra las librerías externas, excluir del control de código fuente la carpeta Packages.

Vamos a ver muy por encima cómo funciona Visual Studio a la hora de trabajar con paquetes, y qué tenemos que tener en cuenta a la hora de trabajar con TFS como control de código fuente cuando usamos NuGet.

Visual Studio y los paquetes NuGet


Cuando usamos paquetes NuGet, los paquetes incluidos en cada proyecto se localizan en el fichero nuget.config. Este fichero es un XML en el que se definen los paquetes utilizados, así como la versión específica de cada uno de ellos que se está utilizando.

Un ejemplo de fichero nuget.config:


<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="GemBox.Spreadsheet" version="41.3.30.1111" targetFramework="net462" />
  <package id="NLog" version="4.4.12" targetFramework="net462" />
  <package id="NLog.Web" version="4.5.0" targetFramework="net462" />
</packages>



En este caso el proyecto usa tres paquetes NuGet: GemBox.Spreadsheet, NLog y Nlog.Web.

Cuando Visual Studio compila el proyecto, si no se hubieran descargado previamente los paquetes, pueden pasar dos cosas:
  • Si tenemos activada la restauración automática de paquetes, Visual Studio descargará todos los paquetes especificados en la carpeta Packages que se encuentra junto a la solución (fichero .sln)
  • Si no tenemos activada esta restauración, nos indicará que no se puede compilar porque falta descargar algunos paquetes.

Si todos los paquetes estaban ya descargados, Visual Studio simplemente compilará la solución.

Lo importante a tener en cuenta es que Visual Studio, para poder compilar, descargará los paquetes en la carpeta Packages. En el caso que nos ocupa, estos paquetes ocupan 25 archivos en 17 carpetas, y ocupan 22,8 MB.

TFS con NuGet


Supongamos que hemos montado una solución de Visual Studio que contiene varios proyectos, y que estos proyectos usan distintos paquetes NuGet.

Al compilar, se crea una carpeta Packages, junto al fichero .sln de la solución, y, como hemos visto, en esta carpeta Visual Studio descarga todos los paquetes (ficheros .dll, ficheros de script para la instalación / desinstalación del paquete, ficheros .js, etc.)

Ahora añadimos nuestra solución a nuestro control de código fuente en TFS, porque tenemos que compartirla con el resto del equipo de desarrollo. Lo que ocurrirá es que TFS añadirá toda la carpeta Packages al control de código fuente, y la subirá al servidor.

Este comportamiento por defecto puede acarrear algunos problemas a futuro:
  • Estamos almacenando en nuestro servidor TFS código que no es nuestro (son librerías pre compiladas externas), y que pueden ocupar bastante espacio. No es difícil que un proyecto use diez o veinte paquetes NuGet, sobre todo en versiones modernas del framework .Net de Microsoft
  • Al actualizar versiones de paquetes, algo que podremos hacer si aparecen nuevas versiones y nos interesa usarlas porque añaden o corrigen alguna funcionalidad, este espacio de almacenamiento se multiplica, porque TFS guardará cada versión en el servidor.
  • Las operaciones de descarga de la última versión, check-in, check-out, branch y merge serán más lentas, porque afectarán a más archivos.
  • En el caso de que configuremos TFS de forma que no permita hacer check-out simultaneo del mismo fichero por dos archivos, a veces los desarrolladores se bloquearán unos a otros sin quererlo, al actualizar un paquete o simplemente porque alteran algo sin darse cuenta.

La cuestión es que, como hemos visto, Visual Studio no necesita los paquetes en sí mismos para poder compilar la solución. Lo que necesita es la definición de los paquetes que se utilizan (el fichero packages.config de cada proyecto). Vamos a ver cómo evitar que se suban los paquetes descargados a su servidor, manteniendo la capacidad de compilar y descargar automáticamente paquetes.

Configurar Visual Studio y NuGet


Para conseguir el comportamiento que deseamos, tenemos que modificar dos ficheros que se encontrarán junto a la solución (fichero .sln). Si los ficheros no existen tendremos que crearlos.

El primer fichero que hay que modificar es el fichero .tfignore. Este fichero almacena las rutas de carpetas y archivos que queremos excluir del control de código fuente. Hay que añadir las siguientes líneas:


packages
!\packages\repositories.config


Esto significa que se excluirá todo lo que haya en la carpeta paclages, y que no se excluirá (sí que se subirá a TFS) el fichero repositories.config. La exclamación delante de la línea está negando la exclusión.

Parece que con esto debería ser suficiente, pero resulta que no. El gestor de paquetes de NuGet mantiene su propia integración con TFS, y tenemos que indicarle que no realice esta integración. Para ellos añadiremos (o editaremos) el fichero NuGet.config. En este fichero introduciremos lo siguiente:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <solution>
    <add key="disableSourceControlIntegration" value="true" />
  </solution>
</configuration>


Si el fichero ya existía deberemos revisarlo para integrar este código.

Esto lo que hace es indicar a NuGet que no se integre con TFS, de forma que los paquetes referenciados no se almacenarán en el servidor.

De esta forma ahorraremos espacio, ganaremos tiempo en algunas operaciones de TFS y evitaremos conflictos en edición simultanea de paquetes entre compañeros del equipo.