The Example: A ClearCase trigger
To customize the behaviour of ClearCase you have to write Perl scripts which can be associated with any ClearCase command as a so called ClearCase trigger (see IBM Rational ClearCase: The ten best triggers). For my example, I needed a trigger that updates a FitNesse Wiki page (the file name is always "content.txt") when it is checked-in to ClearCase. If the file contains a string like "$Revision: \main\MAINLINE_SQE\3 $" the Perl script should update the version information. That's it.Step-by-Step Tutorial
- Install Perl.
- Create a folder "PerlScripts" for the new Perl scripts. We will have two files in this folder: "CiVersionFitnesseTrigger.pl" is the Perl script for the trigger. "CiVersionFitnesseTriggerTests.pl" is the Perl script for the corresponding Unit Tests.
- Download the Test::Simple Perl module. Unpack the gz archive. We will only need the file "Simple.pm" from the folder "lib/Test". Create a folder "Test" as sub folder of our "PerlScripts" folder. Copy the file "Simple.pm" to this "Test" folder.
use Test::Simple tests => 1; # System under test require 'CiVersionFitnesseTrigger.pl'; # Testing is_fitnesse_wiki_page() method ok(FitTrigger::is_fitnesse_wiki_page('content.txt'), 'content.txt is page');
We start defining an empty sub routine and an empty main routine in "CiVersionFitnesseTrigger.pl":
package FitTrigger; sub is_fitnesse_wiki_page { return 0; } # # Main method # 1;We can now run the first unit test and see it failing:
Now we have the infrastructure to start implementation. We fix the first failing test:
package FitTrigger; sub is_fitnesse_wiki_page { my ($file_name) = @_; return $file_name =~ m/^(.*\\)?content\.txt$/ } # # Main method # 1;Now run the unit test again and it succeeds:
We continue the cycle of writing new unit tests and implementing the script step by step. In the end we have 12 unit tests and 1 integration test:
use Test::Simple tests => 13; # System under test require 'CiVersionFitnesseTrigger.pl'; # Testing is_fitnesse_wiki_page() method ok(FitTrigger::is_fitnesse_wiki_page('content.txt'), 'content.txt is page'); ok(FitTrigger::is_fitnesse_wiki_page('c:\content.txt'), 'c:\content.txt is page'); ok(FitTrigger::is_fitnesse_wiki_page('..\content.txt') , '..\content.txt is page'); ok(FitTrigger::is_fitnesse_wiki_page('c:\temp\content.txt'), 'c:\temp\content.txt is page'); ok(!FitTrigger::is_fitnesse_wiki_page('content.txt.old') , 'content.txt.old is not a page'); ok(!FitTrigger::is_fitnesse_wiki_page('somecontent.txt') , 'somecontent.txt is not a page'); ok(!FitTrigger::is_fitnesse_wiki_page('content.txt\something.txt') , 'content.txt\something.txt is not a page'); # Testing getTempFolder() method my $tmpFolder = FitTrigger::get_temp_folder(); ok(defined($tmpFolder) && $tmpFolder ne '' && length($tmpFolder) > 1 , 'temporary folder not empty'); # Testing getTempFile() method my $tmpFile = FitTrigger::get_temp_file(); ok(defined($tmpFile) && $tmpFile ne '' && length($tmpFile) > 1 , 'temporary file not empty'); # Testing update_revision_in_target() method my $testFile = "$tmpFolder\\test.txt"; my $targetFile = "$tmpFolder\\target.txt"; open("TESTFILE", ">$testFile") || &error("Could not open test File $testFile for writing"); print TESTFILE "hallo1\nhallo2\n\$Revision: VERSION_ZZZ \$\n"; close TESTFILE; my $newVersion = 'VERSION_111'; FitTrigger::update_revision_in_target($testFile,$targetFile,$newVersion); open(F,"$targetFile"); my @list =; my $content=join('',@list); close F; my $expectedContent = "hallo1\nhallo2\n\$Revision: VERSION_111 \$\n"; ok($content eq $expectedContent, 'version was updated in target file'); # Testing overwrite_file() method FitTrigger::overwrite_file($targetFile,$testFile); open(F2,"$testFile"); @list= ; my $newContent =join('',@list); close F2; ok($newContent eq $expectedContent, 'file was overwritten with a modified file'); ok(! -e $targetFile, 'modified file is deleted'); # Testing main() method $testFile = "$tmpFolder\\content.txt"; open("TESTFILE", ">$testFile") || &error("Could not open test File $testFile for writing"); print TESTFILE "hallo1\nhallo2\n\$Revision: VERSION_ZZZ \$\n"; close TESTFILE; $ENV{CLEARCASE_PN}=$testFile; $ENV{CLEARCASE_ID_STR}='VERSION_888'; system ("perl CiVersionFitnesseTrigger.pl"); my $expectedContentMain = "hallo1\nhallo2\n\$Revision: VERSION_888 \$\n"; open(F3,"$testFile"); @list= ; my $newContentMain =join('',@list); close F3; ok($newContentMain eq $expectedContentMain, 'perl script has updated content.txt');
The complete implementation in "CiVersionFitnesseTrigger.pl" looks like:
package FitTrigger; sub is_fitnesse_wiki_page { my ($file_name) = @_; return $file_name =~ m/^(.*\\)?content\.txt$/ } sub get_temp_folder { my $tmp_folder = $ENV{TMP}; $tmp_folder = $ENV{TEMP} unless ($tmp_folder); $tmp_folder = "/tmp" unless ($tmp_folder); return $tmp_folder; } sub get_temp_file { my $tmp_folder = get_temp_folder(); return "$tmpFolder\\ccTriggerTmp.$$"; } sub update_revision_in_target { my $source = @_[0]; my $target = @_[1]; my $revision = @_[2]; open("SOURCE", "$source") || &error("Could not open source file $source for reading"); open("TARGET", ">$target") || &error("Could not open target file $target for reading"); while (Running the tests: