In our builds there is sometimes a need (for one or another reason) to copy/create some files that are required during the build, but are not actually artifacts.
As it is a bit problematic to guarantee cleanup/deletion of those files after the build in all cases, they should obviously be stored in some directory that is managed by the build pipeline, so when the build completes or thereafter that directory will be automatically cleaned up.
So far we have been using Build.ArtifactStagingDirectory to get the expected behavior as it is the only one that is
purged before each new build, so you don't have to clean it up yourself.
Still, as such files are not really artifacts, it seems to be slightly inappropriate.
Perhaps there is a better alternative?
$(Build.BinariesDirectory) can also be configured to be purged before each build. That may be more appropriate for temporary build outputs.
However, there's no right answer to this.
I'm slowly replacing traditional jobs with Jenkins pipelines. We've got some jobs which I've previously optimised by only deleting some key files from the workspace of a previous build - thus we end up with incremental builds rather than full ones. FTR this makes our basic builds 3/4 times faster, and I'm keen to preserve it.
I need to delete those files (to simplify real scenario) that contain "cache". I currently use "**/cache" as an include parameter to the Delete Workspace build step. Question: is there something similar already in pipeline steps? I could probably do it using find or similar, but this has to work on Windows too and that has portability implications.
You could use the cleanWS step to clean up certain parts of the workspace. However, it is a plugin you can find here: Workspace Cleanup Plugin.
You can find syntax about a snippet generator for this step at your-jenkins-url/pipeline-syntax/
I've switched away from using cleanWS having used it. Rather I am using the file operations to explicitly delete the files concerned.
The file operations act there and then. The cleanWs acts at the end of a run and can't be relied upon if that run went wrong and did not finish - e.g. syntax error - or that was running a different script.
I've used jenkins for quite a few years but have never set it up myself which I did at my new job. There are a couple questions and issues that I ran into.
Default workspace location - It seems like the latest Jenkins has the default workspace in Jenkins\jobs[projectName]\workspace and is overwritten (or wiped if selected) for every build. I thought that it should instead be in Jenkins\jobs[projectName]\builds[build_id]\ so that it would be able to store the workspace state for every build for future reference?
Displaying workspace on the project>Build_ID page - This goes along with the previous as I expected each 'workspace' for previous builds to show here. Currently in my setup this individual page gives you nothing except the Git revision and what repo changes triggered the build. As well as console output. Where are the artifacts? Where is the link to this build's workspace that was used?
Archiving Artifacts in builds - When choosing artifacts, the filter doesn't seem to work. My build creates a filestructure with the artifacts in it inside workspace. I want to store this and the artifacts filter says it starts at workspace. So I put in 'artifacts' and nothing gets stores (also where would this get stored?). I have also tried '/artifacts' and 'artifacts/*'.
Any help would be great! Thanks!
It does seem like you are confused about several aspects of Jenkins.. I think your question basically boils down to the following.
What is a difference between a workspace and a build?
So, here are some thoughts on this topic:
Builds are historical data. They (usually) don't change like a workspace does during building/checkout.
Builds contain information about a run (e.g. its status, build number, change log, etc) and any artifacts that you tell it to archive (logs, test results, etc). They (usually) don't contain source code like a workspace.
Builds are stored in the Jenkins\jobs\[projectName]\builds\[build_id]\ directory. This is a directory managed by Jenkins and you (usually) do not need to modify anything in this directory. However, workspaces are directories meant for the build and you can do pretty much anything with them and place them anywhere (it does not need to be in the default Jenkins\jobs\[projectName]\workspace directory.
Workspaces should be able to be wiped at any given time. To restore it, just rebuild the job with the same parameters/revision. If you need to keep something after a build, tell Jenkins to archive it before the build is done.
In regard to saving the entire state, I don't think you need to do that. As mentioned in #4, you should be able to reproduce the same build by kicking off the same revision/parameters as the build in question. If you cannot get back to the original state from the same revision/parameters, then that might be something to strive for as debugging is going to be a nightmare. :)
A workspace is an aspect of the project and not a build and that is why there is no link to the workspace from that page. Again, a build is just saved data from a previous run. A project uses the workspace to build stuff and that is why you can get to the workspace from that page.
In regard to how to save artifacts, you must specify the names of the files you want to save. Unless you are trying to save a file called "artifacts", then you should probably use something else. How about **/*.log for all log files? or **/*.xml for all xml files?
Hope this helps.
I have a folder structure setup for my code like so:
MyCodeFolder
-SolutionFileOne.sln
-ProjectFolder1
-ProjectFolder2
-ProjectFolder3
-SolutionFileTwo.sln
-ProjectFolderA
-ProjectFolderB
-ProjectFolderC
-ProjectFolderCommon
Solution one contains projects 1,2,3 and Common and Solution two contains project A, B ,C and Common.
When I come to create my TFS Builds I am getting a problem. If I just add MyCodeFolder in the working folder set up then both builds will succeed but then check-ins against project 2 will kick off a build of solution two and vice versa.
If I map only the folders the solution needs the build fails, which I am guessing is down to the fact I haven't included a mapping to the folder where the solution file is (the MyCodeFolder).
Is there a way I can solve this issue without altering my file structure?
The continuous integration trigger in TFS builds will queue a new build any time an item within that build's workspace is altered. Workspace mappings can only contain folders - you cannot include \ exclude (aka "cloak") individual files within folders.
What you can do is setup your build workspace to use the entire /MyCodeFolder folder. Then, in the build for SolutionFileOne.sln you can cloak ProjectFolderA, ProjectFolderB, and ProjectFolderC. In the build for SolutionFileTwo.sln you can cloak ProjectFolder1, ProjectFolder2, and ProjectFolder3.
This is only a partial solution. Both builds will still get kicked off when someone changes either solution file, or when anything in the ProjectFolderCommon folder is changed. Since you can't cloak the solution files themselves there's no way to avoid both builds getting kicked off on a solution file check-in without changing the structure of your files.
We have a TFS 2008 project with two branches ("Main" and "NewFeature").
Each is a complete, independent "copy" (variant) of the source code.
By changing the workspace mappings, we can map either variant onto our local PCs and have been working with both branches with no problems.
However, if I set up the mappings to switch our build server on to the NewFeature branch (which should simply swap in the NewFeature source code without changing anything else as far as the build server is concerned) I get errors:
There is no working folder mapping for $/Main/Product.sln
i.e. when it is building from the NewFeature branch, something is still looking in the Main branch, even though there are no references anywhere in the source code to this branch. It appears to be caching some reference to Main?!
I have done a completely clean build (deleted the build folder from the server and run the build with /p:ForceGet=true to make sure the mapping is flushed through to the server, and there are no files on the server that might cache the workspace bindings), but this doesn't help.
Any suggestions?
Verify that:
$(SolutionToBuild) uses a relative path when referencing Product.sln
the relative path between $/NewFeature/.../TFSBuild.proj and $/NewFeature/Product.sln is the same as it is in the Main branch.
/ EDIT /
Note, however, it's not important that $/Main and $/Branches/Feature live at the same level in the tree hierarchy. Nor should the local path on the build server matter.* All that matters is what's underneath each branch. If the contents is internally consistent then all of your existing build scripts should work without modification.
For concrete examples of how I like to tie everything together, see my past answers, e.g.:
Modular TeamBuilds
SDLC Mangement for TFS Build Scripts
Where to put my database project in TFS?
How do you share external dependencies between Visual Studio solutions?
My way is not the only way, but I can attest that it works better than all the other variations I've encountered over the years :)
*Frankly, trying to micromanage Team Build can become a lot more painful than the proposed restructuring to your MSBuild scripts. For reliability you have to place your tfsbuildservice.exe.config customizations under version control somewhere...if you own >1 build server (or might in the future) then you have to consider a change deployment strategy...you end up needing a meta-SCM process to manage your SCM process!
I also had this problem when running a build from a branch in TFS 2010. TFS was reporting that "There is no working folder mapping for $/Main/Product.sln" The solution turned out to be to edit the build definition as follows (I am using the "Default Template" build process template—I have not tried this with a custom template):
Go to the Process section/tab of the build definition.
Expand 1. Required and look for Projects to Build. Make sure this entry is pointing to the solution file inside the branch you are building.
Expand 2. Basic and look for Automated Tests. Point this to the correct test settings file in the branch being built.
OK, the results are in - I've found a workaround.
Due to our legacy build processes (build, copy, obfuscate, build custom installers, copy to drop folder), I can't easily place the branch alongside the main branch. It needs to replace it.
So, if I have Main and NewFeature, I wish to unmap Main and map NewFeature in its place (i.e. use "c:\Main" on the build server, and simply change the source code that appears there)
Solution #1 (the most simple, obvious and logical solution) is to use these mappings:
$/NewFeature -> c:\Main
Expected result: NewFeature code structure simply replaces Main, and the build server doesn't know it's on a different branch.
Actual Result: Failure with a "you haven't mapped $/Main even though you're not using it" error.
Solution #2 is to do this:
$/Main -> c:\IgnoreThisFolder
$/NewFeature -> c:\Main
This works (it suppresses the warning and thus allows the build to proceed with MSBuild unaware that it is building in a branch). However, it's ugly and the build gets all the Main branch source code unnecessarily.
Solution #3 (untested, too expensive to try unless I know it'll work much better than #2) is:
Move all the source code (from $/Main, $/Branches/Feature) to $/Branches/Main and $/Branches/Feature to get a consistent hierarchy depth, and rewrite the MSBuild script to work with these new paths.
Hope that I can then map in only the branch I need and edit TFSBuild.proj to redirect it to build in that branch.
(Edit: Yes, this works well. We have now reorganised our entire code structure so that everything (all branches) is under a common root in a single Team Project, and branching/building is no longer a problem - it's easy to do whatever we need now. The trick is to insert a root folder into the hierarchy so that you can branch at any level you like. I've added a small tweak to the build script so that we can pass the branch to build as a parameter to MSBuild, so it's easy to build any variant now. Any branches we don't want to work on can just be cloaked and the build server remains happy.)
Summary
All these solutions (to use the technical term) suck. You have to remap the workspace (in this case, it's not simple: 9 mapping entries are required so it's an error prone and tedious thing to do), edit the TFSBuild.proj, delete all the source code, and run a build with /p:ForceGet=true to switch the build between branches. So it takes about an hour to switch branches. Unbelievable - it should take a few minutes at most!
I realise our project is far from ideally set up, but I can't believe it should be this difficult to branch in TFS (It was a piece of cake in SourceSafe, Accurev, and Perforce, so why so painful in TFS?).
How does everyone else organise their TFS branches? How do you switch developers between branches? How do you switch server builds between branches? Does it really have to be this painful?
When you Edit the build definition there are two places that need to be changed.
Source Settings - Point to your new project location
Process - (This sometimes takes a while to load so be patient) Under Required, change the "items to build" location to the new solution.
Hope this helps.
New update:
As reported in the other answer, I found a workaround that was ok for a short-lived feature branch, but it really didn't work very well. I've since come back to the problem, and the full solution is ridiculously simple:
In the TFSBuild.proj, the path was based on $(BuildProjectFolderPath). This path resolves to a server-side (source control path) like $/Main - not a local path (D:\ServerBuildFolder\Main).
Unfortunately, for historical reasons our source code is split across several team projects, which means the one "branch" is fragmented into several branched folders in Source Control (i.e. $/Main/Code and $/Libraries/Code. You can't create a branch that contains $/Main and $/Libraries). We thus have to reassemble these disparate fragments from Source Control back into a coherent hierarchy using workspace mappings.
This means that Richard was spot on - the relative path from the TFSBuild.proj file to the .sln file was incorrect, because MSBuild/TFS is assuming that the .sln lies within the same Team Project and source control hierarchy (so was looking for $/Main/Libraries.sln instead of $/Libraries/Libraries.sln).
The solution is simple: I replaced $(BuildProjectFolderPath) with a local path (e.g. D:\ServerBuildFolder\Main) for the files, so that the relative reference was resolved in "local space" (after the mappings had been applied), and MSBuild is now running sweetly.
The moral of the story:
1) NEVER use more than one Team Project if there is any chance that you will ever wish to have any kind of reference between those code-bases. Don't be fooled into thinking that a new Team Project will offer some kind of painless logical distinction between applications/libraries. Extra projects have proven to just be an administration nightmare - loads of extra problems for absolutely zero benefit. (It's all one big shared pile under the bonnet, so all the work items and source control folders are still visible in all the projects (!), but it adds a few brick walls that make inter-project links very problematic)
2) Always create a single root-level folder in your Team Project source control, and then put everything else underneath that folder. e.g. For the project "$/Main", create "$/Main/Root" and then put everything from your source hierarchy inside Root.
By following these rules, you will be able to branch the single 'Root' folder in future, and will then only need a single branch and a single extra workspace mapping. This will help you avoid premature baldness.
(In my defence, I would have done it this way to begin with - I'm working with a legacy setup. In defence of the legacy setup, it sounds good on paper but just isn't a Microsoft-supported approach!)
I got this error and all I can fathom is that the definition became corrupt or something. I just redid the process stuff (re-added the solution I was trying to build) and remapped the workspaces and it started working again. HTH.