Automating Microsoft Team Foundation (TFS) check-ins

Have you ever wanted to automate code check-ins to TSF e.g. at the end of the day or at the custom interval you define? That’s easy to do using TFS remote API provided by Microsoft.

In our exercise we are going to use following packages to make the solution working:

<packages>
 <package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net452" />
 <package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net452" />
 <package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.16.204221202" targetFramework="net452" />
 <package id="Microsoft.TeamFoundationServer.Client" version="14.95.3" targetFramework="net452" />
 <package id="Microsoft.TeamFoundationServer.ExtendedClient" version="14.95.3" targetFramework="net452" />
 <package id="Microsoft.VisualStudio.Services.Client" version="14.95.3" targetFramework="net452" />
 <package id="Microsoft.VisualStudio.Services.InteractiveClient" version="14.95.3" targetFramework="net452" />
 <package id="Microsoft.WindowsAzure.ConfigurationManager" version="1.7.0.0" targetFramework="net452" />
 <package id="Newtonsoft.Json" version="6.0.8" targetFramework="net452" />
 <package id="System.IdentityModel.Tokens.Jwt" version="4.0.0" targetFramework="net452" />
 <package id="WindowsAzure.ServiceBus" version="3.3.1" targetFramework="net452" />
</packages>

As a authorization mechanism, we will use token which can be generated on your Visual Studio Online account.
Tokens are more secure and flexible than using standard user/pass credentials as we can safely share it and allow it to expire after a predefined period of time.

so, in our app.config we will have following settings:

 <add key="TfsURL" value="https://your_name.visualstudio.com/DefaultCollection/"/>
 <add key="workspaceName" value="AUTOMATED_CHECKINS"/>
 <add key="tfsServerFolderPath" value="$/remote_folder"/>
 <add key="localWorkingPath" value="D:\MyCodefolder"/>
 <add key="tfsUser" value="not-used"/>
 <add key="tfsPass" value="-your token--"/>
 <add key="tfsDomain" value=""/>

Our main function will look as following (see inline comments):

static void TFSCheckIn(string comment = "")
{
  var TfsURL = new Uri(ConfigurationManager.AppSettings["TfsURL"]);

  //use it for standard user/pass authentication
  //var credential = new NetworkCredential(ConfigurationManager.AppSettings["tfsUser"], ConfigurationManager.AppSettings["tfsPass"], ConfigurationManager.AppSettings["tfsDomain"]);
  //var collection = new TfsTeamProjectCollection(TfsURL, credential);
  //collection.EnsureAuthenticated();

  //token based authentication
  var simpleWebToken = new SimpleWebToken(ConfigurationManager.AppSettings["tfsPass"]);
  var networkCredential = new NetworkCredential(ConfigurationManager.AppSettings["tfsUser"], ConfigurationManager.AppSettings["tfsPass"]);
  
  var basicCredential = new BasicAuthCredential(networkCredential);
  var tfsCredentials = new TfsClientCredentials(basicCredential);
  tfsCredentials.AllowInteractive = false;
  var collection = new TfsTeamProjectCollection(TfsURL, tfsCredentials);
  collection.EnsureAuthenticated();

  var versionControl = (VersionControlServer)collection.GetService(typeof(VersionControlServer));

  Workspace WS = null;
  try
  {
    //Get the current workspace
    WS = versionControl.GetWorkspace(ConfigurationManager.AppSettings["workspaceName"], versionControl.AuthorizedUser);
  }
  catch (Exception)
  { }

  //create workspace if not yet created
  if (WS == null)
  {
     WS = versionControl.CreateWorkspace(ConfigurationManager.AppSettings["workspaceName"], versionControl.AuthorizedUser);
  }

  //map local folder if not already mapped
  if (!WS.IsLocalPathMapped(ConfigurationManager.AppSettings["localWorkingPath"]))
  {
    //Mapping TFS Server and code generated
    WS.Map(ConfigurationManager.AppSettings["tfsServerFolderPath"], ConfigurationManager.AppSettings["localWorkingPath"]);
  }
 
  //download remote changes (check-out)
  WS.Get();

 //auto-resolve conflicts
 Conflict[] conflicts = WS.QueryConflicts(new string[] { ConfigurationManager.AppSettings["tfsServerFolderPath"] }, true);
  
  foreach (Conflict conflict in conflicts)
  {
    if (WS.MergeContent(conflict, false))
    {
     conflict.Resolution = Resolution.AcceptTheirs;
     WS.ResolveConflict(conflict);
    }

   Console.WriteLine("conflict: " + conflict.FileName);
 }

 //Add all files just created to pending change
 int NumberOfChange = WS.PendAdd(ConfigurationManager.AppSettings["localWorkingPath"], true);

 //Get the list of pending changes
 PendingChange[] pendings = WS.GetPendingChanges(ConfigurationManager.AppSettings["tfsServerFolderPath"], RecursionType.Full);

  if (pendings.Any())
  {
    //Auto check in code to Server
     WS.CheckIn(pendings, "Auto check-in code (#changes: " + pendings.Count() + "). " + comment);
  }
 }

Need  custom solution tailored to your business needs? Contact us today!

1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 5.00 out of 5)
Loading...Loading...

Auto publishing reports to Tableau Server

Tableau it’s a great tool for data visualization, however if you are using it a lot, you may want to automate some stuff. One of them is publishing/updating reports to Tableau Server. This is when Tableau Utility Command comes in handy, you can install it on your development server and use in the power-shell script. One of the solutions is to use CI server for auto deployments, you only need to give the git/svn access for users changing the reports or adding new ones.

tableau

Following script can be run as build step in TeamCity to detect workbooks that have been changed recently and publish them automatically to Tableau server. Parent folder of each workbook will be used as project name when publishing. In order to run it, just pass in email notification list and server password – of course you need to configure the params (server url, smtp etc.).

param (
[string]$cmddir = "C:\Program Files\Tableau\Tableau Server\8.2\extras\Command Line Utility", #location where tabcmd has been installed
[string]$server = "https://tableau:81", #this is url of the Tableau server 
[string]$currentDir = (split-path -parent $MyInvocation.MyCommand.Definition) +"\", #current script location
[string]$notificationEmailList = "test1@test.com,test2@test.com", #send email notifications if successful
[string]$admin = "user", #admin account for the server
[string]$pass = "" #to be passed in as param
)
 
function SendEmail($emailTo,$title,$body)
{ 
   $smtp=new-object Net.Mail.SmtpClient("my_smtp_server"); $smtp.Send("sentAs@mydomain.com", $emailTo, $title, $body);
}
 
$global:temp_ = "";
 
#login to Tableau
cd  $cmddir
.\tabcmd login -s $server -u $admin -p $pass
 
 get-childitem -Path $currentDir –recurse |  where-object { 
    $_.LastWriteTime -gt (get-date).AddMinutes(-10) -and $_.FullName.EndsWith(".twb")
  } | 
  Foreach-Object {
 
       [string]$projectName = [System.IO.DirectoryInfo]$_.Directory.Name;
        $global:temp_ += [string][System.IO.Path]::GetFileName($_.FullName) + " | ";
 
       #publish or overwrite workbook on the server
       .\tabcmd publish $_.FullName -r $projectName  -o  
  } 
 
 
#more commands
#.\tabcmd publish "workbook.twbx" -r "project name" -n "Workbook Name" --db-user "" --db-password "" -o
 
 
#log out to release the session
.\tabcmd logout
 
if(-not $global:temp_ -eq "")
{
   SendEmail $notificationEmailList "Tableau report published" "Following report(s) has just been successfully published to Tableau Server: $global:temp_"
}

enjoy!

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...Loading...