How can I get TeamCity to zip a zip file - zip

My problem: I have build on TeamCity that produces a zip file: Files.zip
It contains lots of files, and a zip file is a good container for the files.
Sadly though, and due to legacy reasons, the zip file has no version number in it's title. I would like it to have a version number in it.
Like this: Files.1.2.3.4.zip
I thought that maybe I could create a containing zip, that I can adorn with a version number, like this: ContainingZip.1.2.3.4.zip!Files.zip
So that Files.zip is zipped into another zip! (Madness).
But I cannot work out how to do that through TeamCity and it's artifact paths?
What I feel should work is:
/**/. => Files.Zip => ContainingZip.1.2.3.4.zip!Files.zip
But that just makes Files.Zip
Breaking it into two steps, works not too:
/**/. => Files.Zip
Files.Zip => ContainingZip.1.2.3.4.zip
This doesn't work either as Files.zip doesn't exist when the artifact existence checks are done.
Anyone know how to do this?
(Or do I have to pre-zip in a build step?)
Thanks.

Answer: TeamCity will not let you double zip in the artifact window. You have to use a build step.
Which you can do...
Via a PowerShell build step you can use Compress-Archive if you have PowerShell 5+.
Or there is good infomation here http://stackoverflow.com/questions/1153126/how-to-create-a-zip-archive-with-powershell for older PowerShell versions.
Via an Ant build step:
<?xml version="1.0" encoding="UTF-8"?>
<project name="zipper" default="zip" basedir=".">
<property name="project-name" value="Files.zip" />
<property name="folder-to-zip" value="./FolderToZip/" />
<target name="zip">
<delete file="${project-name}" />
<zip destfile="${project-name}" basedir="${folder-to-zip}" excludes="${project-name}" />
</target>
</project>

You can use parameter references in the artifacts path, so if you define a configuration parameter called, say, VersionNumber that contains the version number value and use an artifact definition of
/**/. => Files.%VersionNumber%.Zip
then you will get the desired output.

Related

Publish of ASP.Net Core project fails with "DestinationFiles" refers to 1 item(s), and "SourceFiles" refers to 2 item(s)

Publish of ASP.Net Core project fails with next error:
"DestinationFiles" refers to 1 item(s), and "SourceFiles" refers to 2 item(s).
They must have the same number of items.
I get an error when I try to publish an ASP.Net Core website to Azure. It builds and runs fine locally. The output prints this:
Task "Copy"
Task Parameter:
SourceFiles=
C:\Users\Mikael\Source\Repos\GoMap-Web\src\Web\appsettings.json
CopyToPublishDirectory=PreserveNewest
RelativePath=appsettings.json
TargetPath=appsettings.json
C:\Users\Mikael\Source\Repos\GoMap-Web\src\Web\appsettings.json
CopyToPublishDirectory=PreserveNewest
RelativePath=appsettings.json
TargetPath=appsettings.json
Task Parameter:DestinationFiles=C:\Users\Mikael\Source\Repos\GoMap-Web\src\Web\obj\Release\netcoreapp1.0\PublishTemp\PublishOutput\appsettings.json
Task Parameter:OverwriteReadOnlyFiles=False
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.Publish.targets(100,5): Error MSB3094: "DestinationFiles" refers to 1 item(s), and "SourceFiles" refers to 2 item(s). They must have the same number of items.
Output Item(s): FileWrites=C:\Users\Mikael\Source\Repos\GoMap-Web\src\Web\obj\Release\netcoreapp1.0\PublishTemp\PublishOutput\appsettings.json
Done executing task "Copy" -- FAILED.
Done building target "_CopyResolvedFilesToPublishPreserveNewest" in project "Web.csproj" -- FAILED.
Done building project "Web.csproj" -- FAILED.
The Microsoft.NET.Publish.targets file (the relevant part, i belive) look like this:
============================================================
CopyFilesToPublishDirectory
Copy all build outputs, satellites and other necessary files to the publish directory.
============================================================
-->
<Target Name="CopyFilesToPublishDirectory"
DependsOnTargets="_CopyResolvedFilesToPublishPreserveNewest;
_CopyResolvedFilesToPublishAlways" />
<!--
============================================================
_CopyResolvedFilesToPublishPreserveNewest
Copy _ResolvedFileToPublishPreserveNewest items to the publish directory.
============================================================
-->
<Target Name="_CopyResolvedFilesToPublishPreserveNewest"
DependsOnTargets="_ComputeResolvedFilesToPublishTypes"
Inputs="#(_ResolvedFileToPublishPreserveNewest)"
Outputs="#(_ResolvedFileToPublishPreserveNewest->'$(PublishDir)%(RelativePath)')">
<!--
Not using SkipUnchangedFiles="true" because the application may want to change
one of these files and not have an incremental build replace it.
-->
<Copy SourceFiles = "#(_ResolvedFileToPublishPreserveNewest)"
DestinationFiles="#(_ResolvedFileToPublishPreserveNewest -> '$(PublishDir)%(RelativePath)')"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForPublishFilesIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForPublishFilesIfPossible)">
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
</Target>
<!--
============================================================
_CopyResolvedFilesToPublishAlways
Copy _ResolvedFileToPublishAlways items to the publish directory.
============================================================
-->
<Target Name="_CopyResolvedFilesToPublishAlways"
DependsOnTargets="_ComputeResolvedFilesToPublishTypes">
<!--
Not using SkipUnchangedFiles="true" because the application may want to change
one of these files and not have an incremental build replace it.
-->
<Copy SourceFiles = "#(_ResolvedFileToPublishAlways)"
DestinationFiles="#(_ResolvedFileToPublishAlways -> '$(PublishDir)%(RelativePath)')"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForPublishFilesIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForPublishFilesIfPossible)">
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
</Target>
I have changed the DestinationFiles="#(_ResolvedFileToPublishPreserveNewest -> '$(PublishDir)%(RelativePath)')" according to another post here but I still get the same failure, and I don't know enough about it to find any clear errors, can anyone offer some insight? If this is affected by the bug mentioned in other posts that has no workaround, what alternative ways could I try to publish the app to azure that might work better?

How to resolve NAnt Error creating FileSet in TeamCity?

I'm using TeamCity to build and deploy into our demo site. We have one configuration called HTML Demo Site and one of the build step is using NAnt to deploy the HTML to the site.
The build file have defined a target:
<target name="deploy-html" description="Deploys the HTML to the demo server">
<echo message="Deploying HTML to the demo server..."/>
<copy todir="\\<server>\<dir>\<client>" includeemptydirs="true" overwrite="true">
<fileset basedir="..\html\_master">
<include name="**\*"/>
<exclude name="node_modules\**"/>
</fileset>
</copy>
</target>
Each time I run the build on TeamCity, it's failing with this error:
C:\tc\w\9149e011dfa8657d\build_scripts\website.build(27,14):
[NAnt output] Error creating FileSet.
[NAnt output] The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
So I tried running on PowerShell to get a list of files that exceed the max length:
Get-ChildItem -Recurse | Where-Object {$_.FullName.Length -gt 248}
But the only files returned are files under the node_modules directory. But in the build file, it's being excluded. So I'm not sure where else to look? Any ideas?
You could try a few things:
Delete the node_modules dir first
Use robocopy /mir in an <exec> task
try putting exclude first before include (not likely, but worth a try)
try changing the path expression to name="node_modules\**\*" or name="**\node_modules\**" or similar
Deleting first worked for me - but the built in nant delete task also has problems so I had to use the rmdir console command
<exec program="${environment::get-variable('WinDir')}\system32\cmd">
<arg value="/c "rmdir /q /s ${Build.BuildFolder}\WebApplication\node_modules"" />
</exec>

Transform external config in a web role

Can slowcheetah transform an external config file in an azure web role? e.g. I have logging info in log4net.config. But the transformed version does not get created when packaged.
I did not manage to get slowCheetah working in my Azure solution.
One alternative you can use is to create complete config files for each environment - e.g. :
log4net.debug.config
log4net.release.config
and copy the contents of these into the log4net.config at buildtime depending on the build configuration chosen.
This is done by adding a build target to your csproj file like so:
<Target Name="BeforeBuild">
<Delete Files="$(ProjectDir)log4net.config" />
<Copy SourceFiles="$(ProjectDir)log4net.$(Configuration).config"
DestinationFiles="$(ProjectDir)log4net.config" />
</Target>
(you may have to modify the paths in the script depending on where in the solution your config files are)
You can find more information on MSBuild and manipulating your .csproj file here and here

Merge Publisher - what does <file action="Copy"> actually do in CruiseControl.Net?

I inherited a project that runs TestComplete scripts from CruiseControl.
For each Script there is an entry in CCnet.Config and each entry ends with the following:
<publishers>
<merge>
<files>
<file action="Copy">
C:\Test\Log\TestCompleteResult\TestWebLog.mht
</file>
</files>
</merge>
<xmllogger />
<statistics />
Which I assumed copies the TestComplete log to that location. However, if I change the location (i.e. to C:\test\log2\TestWebLog.mht), the file still ends up in C:\Test\Log\TestCompleteResult. I have tried shutting down CruiseControl, rebooting the system etc. and the file still ends up in the same location.
I have deleted the directory and file, checked the time stamp and looked at the log file. All indicate that it is a new file created by the most recent run of the TestComplete script, but it always gets put in the same location: C:\Test\Log\TestCompleteResult\TestWebLog.mht.
Is there some place else this path could be defined?
From the CruiseControl.NET Wiki :
Copy: instead of merging the data into the build log, it will copy the specified files into a "build" folder under the artefacts folder for the project
In ccnet.config you can specify an artifact directory for each project into which the build results will be placed.
<project name="Project">
<artifactDirectory>C:\ProjectDir\artifacts</artifactDirectory>
...
</project>
The default merge action is to combine the specified file with the result.xml found in the artifact directory.
The "Copy" merge action copies the specified file into the artifactdirectory\Build folder.
The file you specify in the <file>...</file> tags is the source file that will be copied to the artifact folder.
The <merge> publisher includes an existing file in the build report. If you want to change the location in which the file is generated, you need to change the task configuration (i.e. in the place where TestComplete gets actually invoked).

How to search for files containing a particular text string?

How to search for files containing a particular text string using MSBuild?
Thanks guys! I appreciate all of your quick replies!
I've try Grep but I need to read the xml file to see the result.
I've just found out that we can use the task FilterByContent in MSBuild Extension Pack which gives us a direct result in properties & items. I'd like to share it back to you in case you may need it. An example of usage is as below:
<Target Name="ttt">
<ItemGroup>
<files Include="d:\temp\test\**" />
</ItemGroup>
<MSBuild.ExtensionPack.FileSystem.File TaskAction="FilterByContent" RegexPattern="abbcc" Files="#(files)" >
<Output TaskParameter="IncludedFileCount" PropertyName="out"/>
</MSBuild.ExtensionPack.FileSystem.File>
<Message Text="ttt:$(out)" />
</Target>
Nam.
You can find a "grep" task in the MSBuild Contrib project on CodePlex. Haven't used it myself though.
It's not clear whether you want to search of the text in the name or in the file itself.
If you simply want a list of files that their name match particular (simple) criteria I would suggest using the ItemGroup like this:
The Grep taks from the MSBuild Contrib project would look like this
<PropertyGroup>
<MSBuildContribCommonTasksAssembly>$(MSBuildExtensionsPath)\MSBuildContrib\MSBuildContrib.Tasks.dll</MSBuildContribCommonTasksAssembly>
</PropertyGroup>
<UsingTask TaskName="MSBuildContrib.Tasks.Grep" AssemblyFile="$(MSBuildContribCommonTasksAssembly)" Condition="Exists('$(MSBuildContribCommonTasksAssembly)')" />
<ItemGroup>
<FilesToSearch Include="**\*.cs" />
</ItemGroup>
<!-- very simple search -->
<Grep InputFiles="#(FilesToSearch )" OutputFile="out.xml" Pattern="Error" />
<!-- slightly more complicated search (search and extract info) -->
<Grep InputFiles="#(FilesToSearch )"
OutputFile="out.xml"
Pattern="// (?'Type'TODO|UNDONE|HACK): (\[(?'Author'\w*),(?'Date'.*)\])? (?'Text'[^\n\r]*)" />
The Grep task will generate the out.xml file that can subsequently be used to read information from it and use in the build process.

Resources