I am using PowerShell to modify a series of configuration files within a solution. The solution is under TFS 2010 control.
The solution has many projects and the configuration files are all xml files. The easy part is if I just need to modify a file, I check it out using the checkout command then save the file when I'm done. All good. I go into Visual Studio and see the modified files are updated with pending changes as I would expect
The part I'm having difficulty with is when I have a configuration file that is no longer needed and can be deleted. Using the delete command does, in fact, mark the file for a pending delete, but it does not modify the project file where the deleted file is contained.
When I delete a file via Visual Studio, it automatically checks out and modifies the project file for me. I'm not getting the same result when using a command line delete.
It's not practical for me to do this by hand as I am eliminating over 1,000 files.
Any help would be greatly appreciated!
Thank you.
There are two components at work here. When you are running inside VS, the project system processes all file commands (adds, deletes, edits, etc.) and then calls into the TFS Object Model to actually pend the changes in TFS. The project system is also the one responsible here for removing the reference from the project file. The TFS OM has no knowledge of whether a file is part of a project or not when it is run outside of Visual Studio.
If you have a list of the xml files that you need to delete your best bet is to write a script that reads these in and removes them from the project file (after pending an edit on the project file, of course).
-Taylor,
TFS Version Control Development Lead
Thank you all for your responses. After much digging and trial and error, I figured it out. It was way more simple than I was making it.
In short, I used DTE and ran my script from within VS using the PowerShell console. It went something like this:
$mySolution = $dte.Solution
$projectItem = $mySolution.FindProjectItem($fileToRemove)
if ( $projectItem -ne $null )
{
$projectItem.Remove()
}
Executing the Remove() command on the ProjectItem checks out the corresponding project and edits it accordingly.
Again, thank you again for the time you all took to look at my question and respond. Hope this helps someone else someday!
Related
I'd like to use visual studio to store in source control xml files coming from a server.
I have a request like http://server/query.aspx?FILE_ID=1234 that allows me to download an xml file. Those file are part of our development activities, that's why I'm looking for a convenient way of integrating those file in source control.
I'd like to have a project containing all the xml files I want to check-in in source control and add a pre-build command allowing to download the files, but I did not find any convenient way of doing it.
People have a tendency to forgetting to do it manually, and we have already seen all the possible scenarios: lost files, released version without the ability to know the exact configuration used, ... I'd like to automated this step so that it does not happen again in the future.
I'm sure there is a simple and smart solution, but I could not find it. Any suggestion would be appreciated.
You should be able to use wget in a pre-build action to fetch the latest version of the files. I can't think of a reason why that wouldn't work.
Personally i would consider finding a way to automatically commit those files to source control whenever they change on the server. I've never used tfs, but I assume there is a commandline-client which allows you to commit files in a scripted way. If you don't have any control over when the files change you could do this every N minutes on a machine which is always on.
You can write a (powershell) script that does the fetching, and checkin of the file before your build starts. That's how we fetch external assemblies to be included in our build.
To get you started, take a look at these powershell functions for TFS interaction:
http://www.brokenwire.net/bw/Programming/73/ (TFS 2008)
I've got hold of the Ajax minifier in order to minify some JS and CSS files as part of a build/package/deploy process. It's a great tool and does exactly what we need. However, integrating this into our build/deploy process is proving very difficult.
Ideally, we want to run this tool only when we execute one of our TFS 2010 builds (i.e. NOT a local (Ctrl+Shift+B jobbie) build on a dev machine). Also, we want to replace our currently 'non-minified' files in this scenario with the minified ones (i.e. under the same file name) rather than having a load of additional files named '.min.js' etc.
After a lot of reading I think the key is for a custom build task within the workflow - but I've no idea on how to approach this - espeically as I'm looking to minify files that will have been pulled down directly from our release branch in TFS (i.e. not in someone's local workspace) as part of a TFS 2010 build.
This is the closest discussion I've found to what I'm trying to achieve: Microsoft Ajax Minifier - TFS 2010 Workflow - AjaxMin in the TFS Build
I beleive I will need a custom code activity within the build workflow but have no idea on how to create one to solve this problem. Can anyone shed any light on a process which will allow minification prior to deployment?
OK - thanks to these answers and a lot of research... I came to the following solution :)
Starting with custom code activities, I tried to run the minifier from C# code and then called the activity as part of the workflow. This didn't work as the .dll version of the minifier exposes a couple of methods for compressing both .js and .css files and then makes you open up a StreamWriter of some kind and re-write the file with the compressed string returned from the method (if you're wanting to overwrite your existing files). Pretty intensive opening up and closing files all the day so I wasn't massively happy with that solution. Using the process class to run the .exe with the -clobber option on (for overwriting files) isn't ideal either and produced some odd results (not correctly minifying the files and writing some garbage at the head of each file).
So, you ask, the solution I settled on was to write a PowerShell script (the beginnings of which I got from here - which I then modified slightly to take a command-line parameter - which would be the root folder of your project. The script recursively goes through each file (and each sub-directory's files) and minifies the .css and .js inside. Pretty neat. The bones of which looks something like this:
$ScriptDirectory = $args[0]
Write-Host "Validating directory parameter: $ScriptDirectory"
Write-Host ""
if ((Test-Path -path $ScriptDirectory) -ne $True)
{
#Throw an error of some kind (the parameter passed in isn't a valid directory).
}
$Minifier = “C:\Program Files\Microsoft\Microsoft Ajax Minifier 4\AjaxMin.exe”
get-childitem $ScriptDirectory -recurse -force -include *.js, *.css -exclude *.min.js, *.min.css | foreach-object {&$Minifier $_.FullName -out $_.FullName -clobber}
So we go through each child item of the root folder with an extension of .js or .css (ignoring extensions of .min.* as these have already been compressed).
In TFS, all we need to do is add an InvokeProcess step to execute the PowerShell script in TFS. You can pass your parameter in (the directory to start minifiying) using the Arguments property of the InvokeProcess activity.
To get the directory that TFS build is using to compile your code before it is released (the temporary workspace, if you like), you can use the SourcesDirectory variable available to you in the Run On Agent sequence of the build. This is the location that your files are compiled and packaged up by the TFS build process so anything that gets minified here will end up in the final deployment package.
P.S - the SourcesDirectory is quite high up - you might not want to drill all the way from there to get to your .js and .css files so you mgiht need to specify something like:
SourcesDirectory + "/" + "MyProjectFolder/Scripts"
Make sure you add this InvokeProcess step before your code is deployed in the workflow and hey-presto - you'll have minified .js and .css files, which keep the original file names only as part of a TFS build and not a local one.
Many thanks to all who answered and pointed me in the right direction. I hope this helps someone along the way!
Doing this as a custom code activity is certainly doable, but you'll have to put some effort in it. My suggestion would be:
First follow the TFS 2010 customisation blog from Ewald Hofman at http://www.ewaldhofman.nl/post/2010/04/29/Customize-Team-Build-2010-e28093-Part-4-Create-your-own-activity.aspx to learn aboutr creating custom activities
Then take a look at http://www.ewaldhofman.nl/post/2010/06/01/Customize-Team-Build-2010-e28093-Part-10-Include-Version-Number-in-the-Build-Number.aspx from the same series to implement a mechanism to find all files that conform to a certain pattern. In that example, assemblyInfo.cs files are indexed and their content changed. Replace that by searching for your *.js files.
Release the power of Ajax Minifier on your file selection and replace the original file with the minified one.
Build the activity, include it as a step in the build process template you use in TFS 2010 (also described in the same blog posts) and fine tune it to the point you are satisfied with it.
Alternatively, you can ask the author of the post you have included in your question to share the Minifier TFS activity he created with us :-)
Please, let me know how that works out for you.
You need to implement an Invoke Process Activity so that Minifier gets executed during your TFS builds.
To this purpose you will also have to install the minifier in the Server(s) doing your builds, so so-called Build-Agent(s). By doing that you 'll be ensuring that the Minifier gets invoked only during your TFS-Builds (as opposed to local VS-Builds).
In order to rename your generated output files (*.min.js) you need to implement another custom activity just for that.
Overwritting your checked-in files needs you to first make them writable, this means yet another custom activity (I 've provided in another answer a snippet for that).
The whole choreography is
Invoke Minifier with InvokeProcess --> make checked in files writable --> overwrite checked in files with renamed minified files.
The right way to do this in TFS build is to wrap them in a Sequence.
A good introductory blog post about how to implement an Invoke Process is to be found here.
I have also found the series by E.Hofman of real value.
In the main project of my VS Solution I have a Resources folder with some required external tools. When building and publishing the solution, I get a .\Resources* with all required files there.
So far so good.
However I have to move some files to the parent directory.
My first attempt was do so with the Post Build Events. It works and does move them the correct folder.
Nevertheless in the publish output they still appear in the Resources folder and I need them in the parent one :/
Is there any way to setup the target output path for resources in Visual Studio?
After some research and experimental, I solved my problem.
Still, here's what I learned in the process.
The first attempt was adding the file to the project root and mark it as a resource. After publishing it worked. But having those files in the project root its lame.
Since I needed some *.exe files compiled in another VS solution, added them as a project reference. Gave it a try and it passed the "Publish" test. But still.. not the best way to do it.
After that, with some scripting and a post-build event, I copied the required files to the correct folder. Works.. but after publishing, they don't appear in the package.
However, there is still a possibility with the Mage tool:
http://msdn.microsoft.com/en-us/library/acz3y3te.aspx
This lead to some promissing experiments, however they ended up helping me realize how limited the MS ClickOnce is, so I decided to try other tools.
Here's a good start to follow:
What alternatives are there to ClickOnce?
I had a similar situation once. I found it became more trouble than it was worth to customize output paths and such in Visual Studio, to the extent that I wanted.
I ended up letting Visual Studio do its own thing with regards to file/project structure, and wrote a post-build script to copy everything that was needed into a final, 'publish-ready' directory.
I then set the execution target in Visual Studio to the new location, so I could run/debug as normal, but with the new folder that was organized how I needed it. Careful, I think this is a user project setting; so other developers will need to do this on their machines too, if they so desire.
I do recall changing some output paths and such to make the post-build script more simple. But changing things like that can lead to annoyances when you add new projects to the solution; you might need to configure them to match. It's all a trade-off :)
Two ideas:
Maybe you could move your resources into another project - a project just for resources - and then set their Build Action to Content and Copy To Output to true. Then reference this new project and build the solution. (This may not work as you want, just an idea).
Why not make your resources embedded resources instead. Keep them all within the Resources\ directory and access them programatically?
If I add a new file to a project under TFS source control, it will check out the project file and the corresponding .vspscc file for that project file.
The project file itself changes (to include the new file), but the .vspscc file doesn't change at all. Why bother checking it out? Is there a way to disable it from being checked out and if there is, should I?
It gets checked out because under certain conditions it will be modified..and thus they checked it out as a matter of default. I wouldn't worry about it..it's not hurting anything, and if you disable it, it might bite you badly in the future in a bizarre way.
According to this post of Ben Ryan:
Team Foundation uses these to store lists of files that have been excluded from source control. We leveraged some of the existing SCC integration layer in Visual Studio to integrate Team Foundation, and these files were one of the carryovers. I'll have to check into what the logic was in breaking out these SCC settings into separate files as opposed to putting them in the solution and project files' SCC sections.
This file is a holdover from past VSS/TFS implementations, like Paulo Santos posted.
On the solution level, I have found no functional use for these files. In 10 years of using TFS, I have never seen that file altered. You can delete these .VSSCC files, as I commonly do for my closed source solutions.
But if you delete the solution-level .vsscc file, you will get a non-destructive error message on the first time open of the solution file...only after a new branch is created. All subsequent solution opening will not show the error message again.
My TFS setup standards have the solution file alone in the root folder, all projects are under sub-folders. Since those .vsscc files double the number of files in my root, I always delete them.
On a project level, I leave those files, as my team never opens project files directly, only solution .SLN files.
For my team, I prefer programmer ease of opening solutions over that one-time error message.
When I right-click my solution in the Solution Explorer and choose Properties I get a dialog where I can select the Startup Project.
I sometimes select Current selection (If it is an experimental solution with lots of projects I jump between), but most often it is a Single startup project selected, which would usually be the main WinForms applications or or Console application.
My problem is that whenever I do a treeclean with the tfpt command (Team Foundation Power Tools 2008) this setting is forgotten. So when I try to run my solution the next time, it has defaulted to some random project and I get an error stating that I cannot run a class library or something like that. Which is obvious of course. But where is this setting stored? Why is it forgotten when I do the treeclean? The solution file is still there, right? Isn't solution properties stored there?
Reference 1
Arian Kulp says:
I was struggling with trying to figure
out why a certain solution of mine
wasn’t starting right. It was in VB
with four projects. Upon initial open
it would set a certain project with a
DLL output as startup. If I set the
EXE as startup project, it was fine,
but when I distribute code I always
clean it by removing *.suo and *.user
files, and bin/obj folders. Upon
opening the “cleaned” version, it
would always revert to the DLL project
and fail to F5 nicely. The fix turned
out to be simple, though I’m curious
as to why I needed to do this at all.
In the solution file, there are a list
of pseudo-XML “Project” entries. It
turns out that whatever is the first
one ends up as the Startup Project,
unless it’s overridden in the suo
file. Argh. I just rearranged the
order in the file and it’s good.
I’m guessing that C# is the same way
but I didn’t test it. I hope that
this helps someone!
Reference 2
Setting the StartUp Project
Which project is the "startup" project only has any relevance for debugging, which means it's user metadata from the point of the solution and the projects. Regardless of which project is the "startup" project, the compiled code is the same.
Because of this, the information is stored as a user setting in the Solution User Options file (solution.suo) which accompanies the Solution file (solution.sln). The .suo file "Records all of the options that you might associate with your solution so that each time you open it, it includes customizations that you have made" according to MSDN.
The .suo file is a binary file. If you want to read or change it programatically, you have to use IVsPersistSolutionOpts.LoadUserOptions from the Microsoft.VisualStudio.Shell.Interop namespace.
I suspect that this setting is saved as part of the .suo file created whenever you edit a solution file. This file contains various user settings, such as breakpoints, watch data etc.
I cannot confirm this but that would be my guess.
Unfortunately its not XML its a binary file and not easily edited.
I just wrote a little command line utility for windows called slnStartupProject to solve this. It sets the Startup Project automatically like this:
slnStartupProject slnFilename projectName
I personally use it to set the project after generating the solution with cmake that always sets a dummy ALL_BUILD project as the first project in the solution.
The source is on github:
https://github.com/michaKFromParis/slnStartupProject
Forks and feedbacks are welcome.
Hope this helps!