Monday, November 9, 2015

How to move TFS repository to git

At the company I work for we decided to split one gigantic TFS repository into several smaller ones. We use on prem TFS server which supports multiple git repositories within one project, thus allowing us to track all work items in one place. Unfortunately it’s not the case with TFS repository - you can have just one per project, at least with TFS 2015 (at least prior update 1).

We had the following requirements for new repos: when we split repository we wanted to preserve all version history for specific file/folder/sub-folder, we wanted to preserve association of commits with work item numbers.

Here are steps we took. I’m sure there many solutions, here is just one of them.

1. Convert TFS repository to local git repository using an awesome git-tfs bridge (http://git-tfs.com/):
git tfs clone http://tfs:8080/tfs/collection $/my_project

Depending on repository size it might take a lot of time to get entire version history, so keep that in mind.

2. TFS associates git commits with work items using # sign included into commit message. For example “my commit #105” will associate work item #5 with current commit. git-tfs bridge stores all TFS -> work item associations in git notes, so we need to extract them and append to commit message:

git filter-branch -f --msg-filter 'cat && (git notes show $GIT_COMMIT | grep -E "\[(.*)\]" | sed "s/.*\[\(.*\\)\].*$/#\1/g")' -- --all

3. git-tfs also adds original tfs id references to commit messages, so it makes sense to remove them just to keep commit message cleaner:

git filter-branch -f --msg-filter 'sed "s/git-tfs-id:.*$//g"' -- --all

4. The last step is to actually delete all code that is not required for new repository including version history, but preserve history for the rest. For example if TFS repository contains folders CodeA, CodeB, CodeC, CodeD and only CodeA and CodeD are required, use the following command:

git filter-branch --index-filter 'git rm --cached -qr -- . && git reset -q $GIT_COMMIT -- CodeA CodeD' --prune-empty -- --all

So new repository is ready, just push it to your new location.

Sunday, February 8, 2015

Gulp and bower in ASP.NET MVC

There are many tools, libraries and extensions for Visual Studio to do front end web development. There are NuGet packages that can help combine and minify JS and CSS (Microsoft Ajax Minifier), sass and less transformers (BundleTransformer.SassAndScss, BundleTransformer.Less), reactjs integration (React.Web.Mvc4), angular templates bundling (AngularTemplates.Compile). But there is another very efficient way to do front end development using nodejs, gulp and bower. In my experience it feels more natural than NuGet and MSBuild.

First of all we need to install nodejs: http://nodejs.org/download/. It will also install npm package manager. After that we need to install bower and gulp (don’t forget -g flag to install both packages globally):

npm install -g bower
npm install -g gulp
Now we’re ready to start using these tools with ASP.NET MVC.


Bower


Bower (http://bower.io) will help us manage client side libraries. It stores a list of all dependencies in bower.json file. You can create it manually or just run bower init in console and follow a few steps to generate new bower.json file. Let’s say we want to add angular to our project:

bower install angular

By default bower installs all components to bower_components directory. If you’d like to change that just create .bowerrc file and specify another directory:

{
    "directory": "my_new_directory"
}
For more configuration options see http://bower.io/docs/config/. If you already have bower.json file in your project and need to restore all components, just run bower install command. Here is a sample of bower.json file:

{
  "name": "my_project_name",
  "version": "0.0.1",
  "authors": [],
  "description": "my project description",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "angular": ">=1.3.0",
    "angular-route": ">=1.3.0"
  }
}

Gulp


Gulp (http://gulpjs.com) allows to easily build front end assets: convert sass, less to css, combine and minify css and js, lint them, run unit tests, optimize images and much more. There is a huge ecosystem around it and many libraries that can do pretty much anything with your assets. As an example let's combine and minify JS and CSS.

To do it we need to init our npm app and install several npm modules:
1. npm init
2. npm install gulp gulp-concat gulp-if gulp-minify-css gulp-rev gulp-rev-replace gulp-uglify gulp-useref --save-dev
In order to automatically determine JS and CSS bundles without even using ASP.NET MVC bundling mechanism we're going to use gulp-useref module. We need to wrap our JS and CSS tags into special html comments in our .cshtml files:

<!-- build:css /assets/site.css -->
<link href="/assets/components/foundation/css/normalize.css" rel="stylesheet"></link>
<link href="/assets/components/foundation/css/foundation.css" rel="stylesheet"></link>
<link href="/assets/components/metrics-graphics/dist/metricsgraphics.css" rel="stylesheet"></link>
<link href="/assets/styles/app.css" rel="stylesheet"></link>
<!-- endbuild -->

gulp-useref will cut css links between these html comments, combine css files into one file, minify it and replace with one single link tag that will point to /assets/site.css. The same rules apply to JS assets. Here is full gulp script listing:


var gulp = require('gulp');
var useref = require('gulp-useref');
var uglify = require('gulp-uglify');
var gulpif = require('gulp-if');
var minifyCss = require('gulp-minify-css');
var rev = require('gulp-rev');
var revReplace = require('gulp-rev-replace');

// Concat & Minify JS/CSS
gulp.task('build_assets', function () {
  var assets = useref.assets({
    searchPath: '.'
  });
  gulp.src('Views/**/*.cshtml', {
      base: './'
    })
    .pipe(assets)
    .pipe(gulpif('*.css', minifyCss()))
    .pipe(gulpif('*.js', uglify()))
    .pipe(rev())
    .pipe(assets.restore())
    .pipe(useref())
    .pipe(revReplace({
      replaceInExtensions: ['.cshtml']
    }))
    .pipe(gulp.dest('./obj/Release/Package/PackageTmp'));
});

gulp.task('default', ['build_assets']);

We definitely want to run this script from Visual Studio. We can add gulp script execution to Pre/Post build events. But when we let's say publish our solution to local folder we need to add a bit of xml to our .csproj file. Just add it before project closing tag:


<Target Name="RunGrunt" AfterTargets="CopyAllFilesToSingleFolderForPackage">
  <Exec Command="gulp" />
</Target>

You'll find combined/minified css and js files in published folder as well as modified .cshtml files. This technique allows to get rid of ASP.NET MVC bundles that are going to be deleted in the next version of MVC. See this github issue: https://github.com/aspnet/Mvc/issues/1577.


Please find working example of ASP.NET MVC project with configured gulp and bower support here: https://github.com/vadimi/gulp-aspnet-sample. Run npm install, bower install, open solution in Visual Studio and hit "Publish".

Sunday, October 5, 2014

Combine AngularJS templates in ASP.NET MVC app

Lots of people write pretty heavy JavaScript applications these days, which normally involves client side templates rendering. When we have a lot of templates it potentially might slow down initial application load. AngularJS application lazy loads external files through ajax requests and caches them in $templateCache service in order to reuse them later. One of the possible solutions on how to improve initial load time is to combine multiple files and serve them as one single dependency.

I tried to do it in ASP.NET MVC application recently, but haven’t found any good solutions. There are some nice grunt tasks (for example grunt-angular-templates) to combine AngularJS templates, but I didn’t want to introduce nodejs dependency and implemented an ASP.NET MVC bundle that does pretty much the same thing. Maybe in the next version of Visual Studio grunt/gulp integration is going to be first class citizen, but not for now.

So I created a NuGet package AngularTemplates.Compile that contains ASP.NET MVC bundle and MsBuild task (in case you want to use it outside of ASP.NET MVC pipeline) to combine multiple AngularJS templates. First things first add this package:


PM> Install-Package AngularTemplates.Compile


Then add a bundle with templates:



And render this bundle in your view:


The output result will look similar to this:


Please note that it will generate combined result only when bundle optimizations are enabled (BundleTable.EnableOptimizations = true, or "debug" attribute of "compilation" section in web.config is set to false).

If you prefer MsBuild to precompile and bundle templates/javascripts - there is also available a task:



Packages source are available on github: https://github.com/vadimi/AngularTemplates.Compile

Saturday, September 14, 2013

SharePoint 2013 and Ember.js

Ember.js is great and I'm really enjoying writing apps using it. Well, it's possible to use any modern framework with SharePoint, including Ember.js. Let's see how to write simple Ember.js app using new SharePoint 2013 app model. I'll use SharePoint-hosted app (http://msdn.microsoft.com/en-us/library/fp179887.aspx#SPHosted) for this example - this is an app that is coded using only html and javascript, no server side code at all.

Let's display list of items and item details from some SharePoint list using Ember. First of all we need to create new SharePoint-hosted app:



Then we need to add references to Ember.js and handlebars (the default templating engine). I'll be using ember.js 1.0.0 and handlebars 1.0.0 - latest versions as of this writing. Define the root of our application (div with id "main"):



After all prepartions we can create an instance of Ember.Application - this is the very first step of creating an Ember app:

Ember uses pretty strong conventions for Routes, Controllers and Views. This allows to hide lots of code behind as Ember generates it for us. For example even if we not define controller it will still be generated which is pretty cool I think - we can focus on implementation of our the logic rather than doing some boilerplate code.

We need to define routes for news list and for news details:

This routes map tells us that we need to define NewsRoute and NewsControoler (because of Ember conventions). If those objects will not be found Ember will generate them for us. The default route also will be NewsRoute:

And the last thing we need to do is to create News model and load actual data. It's pretty straightforward on how to use SharePoint javascript object model and proxy requests from app to main site. So here is the code:


And here is the result. This simple SharePoint application loads data from Announcements list from the root site:



Sample code for Visual Studio 2012 has been uploaded here: https://github.com/vadimi/SharePoint-Ember

Monday, May 13, 2013

SharePoint: exclude files from WSP


Publishing of WSPs in Visual Studio is very simple and straightforward. But this process includes absolutely everything into WSP (aspx, ascx, css, js, etc), even if we don’t need them. For example, if we have minified versions of javascript files, we definitely don’t need debug versions in production. SharePoint tooling doesn’t really help us when we need to customize building process for our solutions. But luckily we have MsBuild! I’ll come up with simple solution on how it’s possible to exclude some files from Layouts directory. Everything that will be described below has been tested in Visual Studio 2012 and SharePoint 2010.

When we click Publish button from VS menu, it executes the following MSBuild file:

c:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\SharePointTools\Microsoft.VisualStudio.SharePoint.targets

A closer look to this file shows that we can officially override two targets here: BeforeLayout and AfterLayout. We need to do two things - exclude file from WSP and exclude it from manifest.xml. Excluding from WSP is simple enough. According to Microsoft.VisualStudio.SharePoint.targets file there is EnumeratedFiles ItemGroup created before BeforeLayout target, so we can exclude some files in this target like that:

ExcludedFiles ItemGroup should be defined earlier. FindInEnumeration is simple task that finds files in MSBuild ItemGroup array. Using MSBuild 4.0 we can use little C# snippets in order to create tasks:

After we excluded items from WSP let’s exclude them from manifest.xml. We have to do it separately because manifest files are gathered before BeforeLayout target and we have no control over it. We need to define the following AfterLayout target:

ExcludeFromManifest task reads manifest.xml file from pkg folder and removes ExcludedFiles items from it:

Please note that I added Condition="'$(Configuration)'=='Release'" condition to both targets, so only Release version of WSP will not contain excluded files, Debug version should stay untouched for development mode of course.

Here is the link to the whole build file:

https://gist.github.com/vadimi/5572446

You can just include it in your project, import it through  <Import Project="build-release.targets" /> and modify ScriptsDir, ManifestPath, ExcludedFiles variables according to your project needs. 

Tuesday, July 17, 2012

SharePoint 2013 Preview deployment issues


Today during SharePoint 2013 Preview deployment I got the following error:

ErrorCode<NonDomainNWService>:SubStatus<ES0001>:Service running under Network Service account in workgroup environment is not supported.

The first thing I tried was to install domain controller on my Windows Server 2008 R2 virtual machine. But it didn't help because Standalone option is missing then and it's possible to deploy SharePoint in advanced mode only without SQL Server Express:

http://www.toddklindt.com/blog/Lists/Posts/Post.aspx?ID=204

The I found this link and the solution proposed here did the trick:

http://tomblog.insomniacminds.com/2012/07/17/sharepoint-2013-standalone-installation-issue/

If you experienced the same issue during SharePoint 2013 Preview deployment in Standalone mode on a machine that is not connected to any domain (for example virtual machine) just run psconfig using this command from command line:

PSCONFIG.EXE -cmd Configdb create SkipRegisterAsDistributedCacheHost

And restart psconfig in normal mode to finish configuration.

Most likely you'll have some issues with default content population, but SharePoint configuration step will be already completed. So just create new site collection and enjoy.

Thursday, April 5, 2012

SharePoint 2010 version


It's very common task to find out the version of current SharePoint farm.

I typically use two approaches.

1. Simple PowerShell script:

(Get-SPFarm).BuildVersion

This command will return the following screen:



2. Go to Central Administration -> Manage servers in this farm and you'll see something like that:


Hope this helps.