2011-10-28 10 views
6

Problema: Estoy configurando TeamCity como servidor de compilación para un proyecto ASP.NET MVC. Estoy usando Powershell con psake para ejecutar msbuild contra nuestro archivo .csproj y crear un paquete desplegable. Desde el servidor de compilación, puedo abrir PowerShell, ejecutar el script y, dado que no hay cambios en el código fuente, msbuild no regenera los archivos DLL del proyecto. PERO, cuando invoco el mismo script desde la interfaz web de TeamCity, msbuild SIEMPRE reconstruye y regenera los archivos DLL aunque no haya cambios. No es lo que debería hacer AFAIK.El paso de compilación desencadenado por TeamCity siempre se genera, incluso cuando no hay cambios

Reduje este problema a un solo paso. Para simplificar, configuré mi configuración de TeamCity para que no use ningún control de fuente, ejecuta un solo paso de compilación "powershell" que llama a mi secuencia de comandos de powershell.

La secuencia de comandos PowerShell se ejecuta un único comando:

exec { &$msbuild $ProjectFile /t:Package "/p:PackageLocation=$PackageFile;OutDir=$TempPath;Configuration=$Config;SolutionDir=$BaseDir\Source\" /v:m } 

Cuando llamo a la secuencia de comandos manualmente desde una línea de comandos PowerShell, veo:

CoreCompile: 
Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files. 

Cuando llamo el mismo guión exacto a través TeamCity , veo:

[11:11:26]: CoreCompile: 
[11:11:26]: c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Csc.exe /noconfig ... 
<SNIP> 
[11:11:32]: CopyFilesToOutputDirectory: 
[11:11:32]: Copying file from "obj\Demo\Website.Web.dll" to "d:\deploy\Build\package\Demo\temp\Website.Web.dll". 
[11:11:32]: Website.Web -> d:\deploy\Build\package\Demo\temp\Website.Web.dll 
[11:11:32]: Copying file from "obj\Demo\Website.Web.pdb" to "d:\deploy\Build\package\Demo\temp\Website.Web.pdb". 
[11:11:32]: _CopyWebApplicationLegacy: 
[11:11:32]: Copying Web Application Project Files for Website.Web 
[11:11:32]: Copying file from "obj\Demo\Website.Web.dll" to "d:\deploy\Build\package\Demo\temp\_PublishedWebsites\Website.Web\bin\Website.Web.dll". 
[11:11:32]: Copying file from "obj\Demo\Website.Web.pdb" to "d:\deploy\Build\package\Demo\temp\_PublishedWebsites\Website.Web\bin\Website.Web.pdb". 
[11:11:32]: Copying file from "d:\deploy\Build\package\Demo\temp\Website.Data.dll" to "d:\deploy\Build\package\Demo\temp\_PublishedWebsites\Website.Web\bin\Website.Data.dll". 
[11:11:32]: Copying file from "d:\deploy\Build\package\Demo\temp\Website.Data.pdb" to "d:\deploy\Build\package\Demo\temp\_PublishedWebsites\Website.Web\bin\Website.Data.pdb". 

Cualquier idea por qué la ejecución de este script desde TeamCity causa msbuild a detectar cambios y reconstruir, pero ejecutar exactamente el mismo script manualmente ¿no?

ACTUALIZACIÓN: Pensando Esto puede ser causado por algún capricho con el corredor TeamCity Powershell, he intentado hacer un archivo por lotes que pasa la secuencia de comandos en Powershell.exe y lo llamó con el corredor de la línea de comandos:

C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe -NonInteractive -File D:\deploy\Build\run-build.ps1 && exit /b %ERRORLEVEL% 

y obtengo exactamente el mismo comportamiento. Si llamo a este archivo por lotes desde la línea de comandos, el msbuild omite la compilación. Si lo llamo desde TeamCity, los archivos DLL se vuelven a compilar.

ACTUALIZACIÓN # 2: Eureka! Inicié la depuración de diagnóstico en msbuild y encontré la causa de la recompilación forzada. Es causado por el objetivo GenerateTargetFrameworkMonikerAttribute. Aquí está la clave de bits de la salida del registro:

[15:23:28]: Target "GenerateTargetFrameworkMonikerAttribute" in file "c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets" from project "d:\deploy\source\Website.Data\Website.Data.csproj" (target "BeforeCompile" depends on it): 
[15:23:28]: Building target "GenerateTargetFrameworkMonikerAttribute" completely. 
[15:23:28]: Output file "C:\TeamCity\buildAgent\temp\buildTmp\.NETFramework,Version=v4.0.AssemblyAttributes.cs" does not exist. 
[15:23:28]: Using "WriteLinesToFile" task from assembly "Microsoft.Build.Tasks.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". 
[15:23:28]: Task "WriteLinesToFile" 
[15:23:28]: Done executing task "WriteLinesToFile". 
[15:23:28]: Done building target "GenerateTargetFrameworkMonikerAttribute" in project "SMM.Data.csproj". 

Parece que este objetivo crea/actualiza un archivo AssemblyAttributes en el directorio temporal como se especifica en la variable de entorno TEMP. Aparentemente TeamCity anula la variable de entorno TEMP y lo establece en: C: \ TeamCity \ buildAgent \ temp \ buildTmp y este directorio se limpia antes de cada compilación.

puedo ver esto si llamo Get-ChildItem Env: desde powershell:

TEMP       C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp 
TMP       C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp 

Pero si yo lo llamo desde el script de PowerShell como se llama desde TeamCity:

TEMP       C:\TeamCity\buildAgent\temp\buildTmp    
TMP       C:\TeamCity\buildAgent\temp\buildTmp 

La pieza clave es que después de este archivo se regnerated:

[15:23:28]: Building target "CoreCompile" completely. 
[15:23:28]: Input file "C:\TeamCity\buildAgent\temp\buildTmp\.NETFramework,Version=v4.0.AssemblyAttributes.cs" is newer than output file "obj\Demo\SMM.Data.pdb". 

Y esta es la razón por la totalidad del proyecto es conseguir r ecompilado.

Cuando ejecuto la secuencia de comandos de Powershell, el directorio temporal no se cambia ni se limpia y la compilación se ejecuta como se esperaba.

Entonces, ¿alguien sabe cómo puedo cambiar el directorio en el que se creó este archivo AssemblyAttributes o decirle a TeamCity que use un directorio TEMP diferente? Tengo que creer que este es un problema que otros se han topado.

Gracias!

Respuesta

6

Así que, como he mencionado en "Actualización # 2" por encima, el problema parece ser causado por 2 cosas: - TeamCity establece el entorno TEMP y TMP vars a su propio directorio temporal - TeamCity "limpia" esta temperatura directorio antes de cada construir - Parte del proceso msbuild corre un objetivo GenerateTargetFrameworkMonikerAttribute que actualiza un archivo específico en el directorio especificado por la variable de entorno TEMP - causando que el compilador lo que necesita para volver a compilar todo el proyecto

una vez que pensé esto, encontré una respuesta aplicable en esta pregunta no relacionada: In Visual Studio 2010 why is the .NETFramework,Version=v4.0.AssemblyAttributes.cpp file created, and can I disable this?

Así que añadí:

<Target Name="GenerateTargetFrameworkMonikerAttribute" /> 

a ambos de los proyectos en la solución que compilan a DLL y funcionó.

+0

Pude reproducir el problema y estaba llegando a conclusiones similares. De todos modos, bueno que encontraste la respuesta. Acepta tu respuesta cuando puedas. – manojlds

+0

+1 para una explicación completa y genial para compartirlo! –

+0

Parece que TeamCity hace lo que tiene que hacer ya que dependiendo de las carpetas temporales o en cualquier otra carpeta específica no es una buena idea en CI. –

0

Como una variación de la respuesta de obliojoe, puede copia de seguridad y restaurar estos archivos a/desde la carpeta TEMP, si usted no quiere o no puede cambiar los archivos de proyecto individuales:

  1. primer intento de restaurar los archivos a partir de una copia de seguridad:

    copy temp\*.* %%temp%% /y 
    echo AssemblyAttributes restore attempted 
    
  2. a continuación efectuar su paso (s) de construcción utilizando TeamCity acumulación corredor

  3. de copia de seguridad de los archivos:

    mkdir temp 2> nil 
    copy %%temp%%\*AssemblyAttributes.cs temp /y 
    echo AssemblyAttributes files saved 
    

Ambos archivos por lotes tienen que ejecutar desde el mismo directorio.

Observe el ECHO final en estos archivos por lotes, está ahí para garantizar la salida exitosa (código de error 0).

Cuestiones relacionadas