Introduction
Some companies use a migration plan as the basis for a project release. Migration Plan (typically in Excel) contains the release file details such as release file name, path and the version number in the source control. Each worksheet in the migration plan contains the entries for one type of release source information (i.e. the C++ worksheet contains .cpp information and the EXEDLL worksheet contains the executable files information for the release). Please find a sample migration plan below:
Normally migration plans will be updated by the developers once the development phase is over. Based on this release migration plan, build engineers either fetch the sources from source control and build the sources to create the installation package, or fetch only the executables (if the source control contains the properly built executables) and create the installation package.
To automate the project release process in such scenarios, I tried to develop a Windows application that fetches the sources automatically from Visual SourceSafe based on an Excel based migration plan.
Here is the UI for this application:
The user will enter VSS details (such as user name, password and INI file), the Excel migration-file path and the destination folder (where the files from VSS would be copied). In this application, the user has the choice to fetch all the sources or those specified in chosen work sheets (under Extract Files group box).
Building the Application
Start by creating a new Windows Application project:
Design the user interface as shown below and name the controls appropriately:
On clicking the “Get Files” button:
- The project will open the migration file (Excel file) and fetch the file details (file name, path and version number).
- Copy the files to the destination folder from Visual SourceSafe.
We will create a class to handle the Excel operations such as opening the Excel file, closing the Excel file, and getting the file details (i.e. file path, name and version number in VSS) from the various worksheets.
We will create another class to handle VSS operations such as opening the VSS database, closing the VSS database and extracting the files from VSS to the local system.
We can prepare two separate components to handle the above cases. To make the application simple, I created both the classes in the application itself.
To extract the file details from the Excel migration file, create a new interface (IMigrationFile
) with three methods: one method to open the migration file, a second method to close the migration file, and a third method to get the file details based on the worksheet name).
interface IMigrationFile
{
string OpenMigrationFile(string strMigrationFile);
string CloseMigrationFile();
ArrayList GetFileDetails(string strWorkSheet);
};
Add a new class (ExclMigrationFile.cs) to the project using Projects->Add New Item. This class will implement the IMigrationFile
interface.
To access the Excel automation methods, we need to add a reference to the Excel object using Project->Add Reference under COM tab.
Each worksheet contains the file path, file name and version number. Create a structure to store these values while extracting the from the worksheet.
public struct FileDetails
{
public string FilePath;
public string FileName;
public int VersionNo;
};
Now we need to provide the implementation for the IMigrationFile
interface methods. Before implementing these interface methods, add the following private
variables to the class.
private ExclVSS._Application exclVSSApp=null;
private ExclVSS.Sheets exclVSSWorkSheets=null;
Now provide the implementation for the OpenMigrationFile
method.
public string OpenMigrationFile(string strMigrationFile)
{
try
{
this.ExclApp= new Microsoft.Office.Interop.Excel.ApplicationClass();
this.ExclApp.Workbooks.Open(strMigrationFile,vk_update_links,
vk_read_only, vk_format, vk_password,vk_write_res_password,
vk_ignore_read_only_recommend, vk_origin,vk_delimiter,
vk_editable, vk_notify, vk_converter,
vk_add_to_mru,vk_local, vk_corrupt_load);
this.ExclWorkSheets=this.ExclApp.Worksheets;
}
catch(Exception e)
{
return e.ToString();
}
return "";
}
Next we provide the implementation for the CloseMigrationFile
method:
public string CloseMigrationFile()
{
try
{
this.ExclApp.Workbooks.Close();
}
catch(Exception e)
{
return e.ToString();
}
return "";
}
The third interface method GetFileDetails
needs to be implemented now. This method extracts the file details from the user choice worksheet. This method uses a helper function (GetFileDetails
) to extract the file details.
public ArrayList GetFileDetails(string strWorkSheet)
{
ArrayList alFileList=new ArrayList();
foreach(Excl.Worksheet exclWorkSheet in exclWorkSheets)
{
if(strWorkSheet == exclWorkSheet.Name)
{
GetFileDetails(exclWorkSheet, ref alFileList);
break;
}
}
return alFileList;
}
private void GetFileDetails(Excl.Worksheet exclWorkSheet,
ref ArrayList alFileDetails)
{
exclWorkSheet.Activate();
int nRowCount=exclWorkSheet.UsedRange.EntireRow.Count;
for(int i=2;i<=nRowCount;i++)
{
Excl.Range rangeCPP=exclWorkSheet.get_Range("A"+i.ToString(),
"C" + i.ToString());
System.Array array = (System.Array)rangeCPP.Cells.Value2;
FileDetails fileDetails=new FileDetails();
fileDetails.FilePath=(string)array.GetValue(1,1).ToString();
fileDetails.FileName=(string)array.GetValue(1,2).ToString();
fileDetails.VersionNo=
Convert.ToInt32(array.GetValue(1,3).ToString());
alFileDetails.Add(fileDetails);
}
}
To get the files from VSS, create a new interface (ISourceControl
) with three methods to open the VSS database, to close the VSS database, and to get the specified file from VSS.
interface ISourceControl
{
string OpenSourceControl(string UserName,
string Password, string INIPath);
string CloseSourceControl();
string GetFileFromSourceControl(string FilePath,
string DestinationPath, int VersionNo,int Flags);
};
Add a new class (VSS.cs) to the project using Projects->Add New Item. This class will implement the ISourceControl
interface.
To access the Visual SourceSafe automation methods, we need to add a reference to the VSS object using Project->Add Reference under COM tab.
Now provide the implementation for the ISourceControl
interface methods:
public string OpenSourceControl(string UserName,
string Password, string INIPath)
{
vssDatabase = new SourceSafeTypeLib.VSSDatabase();
try
{
vssDatabase.Open (INIPath, UserName, Password);
}
catch(Exception e)
{
return e.ToString();
}
return "";
}
public string CloseSourceControl()
{
try
{
vssDatabase = null;
}
catch(Exception e)
{
return e.ToString();
}
return "";
}
public string GetFileFromSourceControl(string FilePath,
string DestinationPath,int VersionNo,int Flags)
{
SourceSafeTypeLib.VSSItem vssItem;
SourceSafeTypeLib.VSSItem vssVersionItem;
try
{
vssItem = vssDatabase.get_VSSItem(FilePath, false);
vssVersionItem=vssItem.get_Version(VersionNo);
vssVersionItem.Get(ref DestinationPath, Flags);
}
catch(Exception e)
{
return e.ToString();
}
return "";
}
We have done with the IMigrationFile
and ISourceControl
implementation.
Now provide the implementation for the UI control handlers.
Implementation for OnClick
of the Get Files button:
private void btnGetFiles_Click(object sender, System.EventArgs e)
{
Initialize_OpenExcelVSS();
ExtractFiles();
Close_ExcelVSS();
}
Here are the operations that this method will perform:
Step 1:
Open the Excel file and the VSS database using IMigrationFile
and ISourceControl
interface methods.
private void Initialize_OpenExcelVSS()
{
strUserName=txtUserName.Text;
strPwd=txtPwd.Text;
strINIPath=txtIniName.Text;
strExcelPath=txtExcel.Text;
strDestPath=txtDest.Text;
this.iExcel=new AutoMigration.ExcelMigrationFile();
this.iVSS=new AutoMigration.VSS();
this.iExcel.OpenMigrationFile(strExcelPath);
this.iVSS.OpenSourceControl(strUserName,strPwd,strINIPath);
}
Step 2:
Get the file details (file path, file name and version number) from the Excel worksheet.
private void ExtractFiles()
{
if(true==chkCPP.Checked)
{
ArrayList al=null;
al=this.iExcel.GetFileDetails(strCPP);
GetVSSFiles(al);
}
if(true==chkVB.Checked)
{
ArrayList al=null;
al=this.iExcel.GetFileDetails(strVB);
GetVSSFiles(al);
}
if(true==chkXML.Checked)
{
ArrayList al=null;
al=this.iExcel.GetFileDetails(strXML);
GetVSSFiles(al);
}
if(true==chkEXE.Checked)
{
ArrayList al=null;
al=this.iExcel.GetFileDetails(strEXE);
GetVSSFiles(al);
}
if(true==chkASP.Checked)
{
ArrayList al=null;
al=this.iExcel.GetFileDetails(strASP);
GetVSSFiles(al);
}
}
Step 3:
Extract the files from VSS based on the file path, name and version number (which we got in the above step).
private string GetVSSFiles(ArrayList alFiles)
{
string strFilePath;
try
{
System.Collections.IEnumerator myEnumerator = alFiles.GetEnumerator();
while ( myEnumerator.MoveNext() )
{
FileDetails fileDetails=(FileDetails) myEnumerator.Current;
strFilePath=fileDetails.FilePath+fileDetails.FileName;
this.iVSS.GetFileFromSourceControl(strFilePath,strDestPath,
fileDetails.VersionNo,Flags);
}
}
catch(Exception e)
{
return e.ToString();
}
return "";
}
Step 4:
Close the Excel file and the VSS database.
private void Close_ExcelVSS()
{
this.iExcel.CloseMigrationFile();
this.iVSS.CloseSourceControl();
this.iExcel=null;
this.iVSS=null;
}
Implementation for browse buttons:
private void btnINI_Click(object sender, System.EventArgs e)
{
OpenFileDialog openINIFile = new OpenFileDialog();
openINIFile.DefaultExt = "ini";
openINIFile.Filter = "INI Files (*.ini)|*.ini";
openINIFile.ShowDialog();
txtExcel.Text=openINIFile.FileName;
}
private void btnExcel_Click(object sender, System.EventArgs e)
{
OpenFileDialog openExcelFile = new OpenFileDialog();
openExcelFile.DefaultExt = "xls";
openExcelFile.Filter = "Excel sheets (*.xls)|*.xls";
openExcelFile.ShowDialog();
txtExcel.Text=openExcelFile.FileName;
}
This is the first step of automating the migration plan release process. Next step would be automatically building the fetched sources (I’ll cover this topic in the next article).
Before testing the application, make sure that the user has the proper rights to connect to Visual SourceSafe and to fetch the sources.
Reference and Further Reading
Documents in MSDN:
- Tim Winter. Visual SourceSafe 6.0 Automation. September 1998.