Requirements:
- cygwin — windows bash scripting utility
- mailsend — free email notification utility
- msbuild — standard .NET Framework build utility
- team explorer — source control utility (tfs)
Features:
- auto build with Debug and Release configurations
- builds separately every commited TFS changeset
- current date appended to MSI file name
- different email notifications for successful and failed builds with description
Algorithm structure:
- This script should be called periodically, for example, every 10 minutes to check for the new changesets with Windows task scheduler.
- In case changeset hasn’t built yet (there are no folders with a given building changeset number), we have to start build process.
- Get source code from TFS server for the given changeset number.
- Build Debug and Release configurations for the given changeset. Log files are stored in destination folders.
- Debug/[changesetnumber]
- Release/[changesetnumber]
- Send notifications emails for the selected users at the end of a build process for the given changeset:
- in case of successful build, email contains network links to the destination folders with msi installation files. Also changeset commiter user name included, comment and edit files list.
- in case of failed build, debug.log and release.log build process files attached to the email letter. Also log files copies are stored in destination folders of build server.
Main projects autobuild.bat build file example:
c:\cygwin\bin\bash.exe --login -i /cygdrive/c/WT_Build/firstproject.sh >>C:\WT_Build\log.txt 2>&1
c:\cygwin\bin\bash.exe --login -i /cygdrive/c/WT_Build/secondproject.sh >>C:\WT_Build\log.txt 2>&1
Script file example firstproject.sh:
#!/bin/bash
SERVER="http://tfsserver:portnumber/"
SERVERPATH='$/TFSProjetDirectory/trunk/ProjectName/'
WORKSPACE="WORKSPACENAME"
BUILD_PARAMETERS="/p:PostBuildEvent=""" #skip post build events
CC_SUCCESS_BUILD="firstemail@mailserver.com,secondemail@mailserver.com"
CC_FAILED_BUILD="firstemail@mailserver.com"
PROJECT_BUILD_DIR="ProjectNameSuffix"
GETPATH="$(cygpath -u 'C:\WT_Build\TFSProjetDirectory\trunk\ProjectName')"
DOTNETPATH="$(cygpath -u 'C:\WINDOWS\Microsoft.NET\Framework\v3.5\')"
SETUPPATH="$GETPATH"/SetupProjectDirectory
SETUPPROJECTPATH="$(cygpath -w $SETUPPATH/SetupProjectName.wixproj)"
SETUP_DEBUG_EN_RESULT="$SETUPPATH"/bin/Debug/en-US/MsiOutputName*.msi
SETUP_DEBUG_RU_RESULT="$SETUPPATH"/bin/Debug/ru-RU/MsiOutputName*.msi
SETUP_RELEASE_EN_RESULT="$SETUPPATH"/bin/Release/en-US/MsiOutputName*.msi
SETUP_RELEASE_RU_RESULT="$SETUPPATH"/bin/Release/ru-RU/MsiOutputName*.msi
#include file with auto build utilities
source /cygdrive/c/WT_Build/auto_build_utils.sh
echo "----------------------------------------------------------"
echo "Checking TFS for the new changesets...."
CreatePath $GETPATH
#we load last solution history. 15 latest changesets are taken
$TF history $SERVERPATH /version:T /recursive /stopafter:15 /noprompt /server:$SERVER |
tail -n+3 |
sort |
while read changeset commiter other
do
if [ ! -d "$BUILDPATH"/Debug/"$changeset" ] && [ ! -d "$BUILDPATH"/Release/"$changeset" ] ; then
# Control will enter here if destination DIRECTORY doesn't exist
DeleteCode $GETPATH
CreatePath $GETPATH
CreatePath "$BUILDPATH"/Debug/"$changeset"
CreatePath "$BUILDPATH"/Release/"$changeset"
getCodeLogfile=$BUILDPATH"/Release/"$changeset"/getcode.log"
debugBuildLogfile=$BUILDPATH"/Debug/"$changeset"/debug.log"
releaseBuildLogfile=$BUILDPATH"/Release/"$changeset"/release.log"
GetCode $changeset $getCodeLogfile
BuildChangeset $changeset $debugBuildLogfile $releaseBuildLogfile
#Project name considered to be like MyProjectSetupFileName.0.9.4102.30983_110326_171041_EN_Debug.msi
setupDebugEnOutput="$BUILDPATH"/Debug/"$changeset"/`basename $SETUP_DEBUG_EN_RESULT | cut -d'.' -f1,2,3,4,5`_"$DATE"_EN_Debug.msi
setupDebugRuOutput="$BUILDPATH"/Debug/"$changeset"/`basename $SETUP_DEBUG_RU_RESULT | cut -d'.' -f1,2,3,4,5`_"$DATE"_RU_Debug.msi
setupReleaseEnOutput="$BUILDPATH"/Release/"$changeset"/`basename $SETUP_RELEASE_EN_RESULT | cut -d'.' -f1,2,3,4,5`_"$DATE"_EN_Release.msi
setupReleaseRuOutput="$BUILDPATH"/Release/"$changeset"/`basename $SETUP_RELEASE_RU_RESULT | cut -d'.' -f1,2,3,4,5`_"$DATE"_RU_Release.msi
CopyResults $SETUP_DEBUG_EN_RESULT $setupDebugEnOutput
CopyResults $SETUP_DEBUG_RU_RESULT $setupDebugRuOutput
CopyResults $SETUP_RELEASE_EN_RESULT $setupReleaseEnOutput
CopyResults $SETUP_RELEASE_RU_RESULT $setupReleaseRuOutput
MailBuildReport $changeset $commiter $debugBuildLogfile $releaseBuildLogfile
echo -e "\n"
fi
done
echo Done.
Auto build utilities file auto_build_utils.sh:
#!/bin/bash
TF="TF.exe"
MSBUILD="MSBuild.exe"
#http://www.muquit.com/muquit/software/mailsend/mailsend.html">http://www.muquit.com/muquit/software/mailsend/mailsend.html
MAILSEND="$(cygpath -u 'C:\WT_Build\mailsend.exe')"
DATE=`date +%y%m%d_%H%M%S`
TFSPATH="$(cygpath -u 'C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE')"
BUILDPATH="$(cygpath -u 'C:\WT_Build\Builds\'$PROJECT_BUILD_DIR)"
PATH=${PATH}:"$TFSPATH":"$GETPATH":"$DOTNETPATH"
function CreatePath {
echo -e "\n"
echo Checking directory: $1
mkdir -p $1
}
function BuildChangeset {
echo -e "\n"
echo Building Release changeset $1...
$MSBUILD $SETUPPROJECTPATH /t:Rebuild /p:Configuration=Release $BUILD_PARAMETERS >$3 2>&1
echo -e "\n"
echo Building Debug changeset $1...
$MSBUILD $SETUPPROJECTPATH /t:Rebuild /p:Configuration=Debug $BUILD_PARAMETERS >$2 2>&1
}
function GetCode {
echo -e "\n"
echo Getting code for changeset $1...
pushd $GETPATH
$TF get $SERVERPATH /version:C$1 /recursive /noprompt /overwrite /force >$2 2>&1
popd
}
function DeleteCode {
echo Deleteting path: $1
rm -r -f $1
}
function CopyResults {
echo -e "\n"
echo Copying $1
echo ' 'to $2
cp $1 $2
}
function MailBuildReport {
if (cat $3 | grep -q "Build succeeded") && (cat $4 | grep -q "Build succeeded")
then
( echo 'Release build link \\Vm-wt-build\Builds\'$PROJECT_BUILD_DIR'\Release\'$1 &&
echo 'Debug build link \\Vm-wt-build\Builds\'$PROJECT_BUILD_DIR'\Debug\'$1 &&
echo -e "\n\n" &&
$TF changeset /server:$SERVER /noprompt $1 ) |
iconv -f CP1251 -t UTF-8 |
$MAILSEND -d share.server.local -smtp share.server.local -cc $CC_SUCCESS_BUILD -t $2@server.com -f fromuser@server.com -sub "$2: $PROJECT_BUILD_DIR Build for changeset $1 READY"
else
firstLog="$(cygpath -w $3)"
secondLog="$(cygpath -w $4)"
$TF changeset /server:$SERVER /noprompt $1 |
iconv -f CP1251 -t UTF-8 |
$MAILSEND -d share.server.local -smtp share.server.local -cc $CC_FAILED_BUILD -t $2@server.com -f fromuser@server.com -sub "$2: $PROJECT_BUILD_DIR Build changeset $1 FAILED." -a "$firstLog,text/plain" -a "$secondLog,text/plain"
fi
}