Tuesday, December 2, 2014

Perforce trigger script to enforce JIRA ID (Perl)

A perforce trigger script written in Perl to enforce JIRA ID on Perforce changelist submission. This script also connects to JIRA server to make sure the submitted JIRA ID is a valid one.

Create a properties file p4trigger.properties with required information
cat p4trigger.properties
# Perforce pre-commit trigger to check jira-id configuration file
# %serverport%  It comes from trigger

p4user = **** 
p4port = ****:1666
p4passwd = ************************************
jiraProjects = AAAA BBBB
jiraURL = https://jira.com:8443
jiraLogin = ******
jiraPWD = /export/*****/******/****.txt


Now a perl module Utilities.pm, which consists re-usable functions.


cat Utilities.pm


package Utilities;
use strict;
use Exporter;
use Data::Dumper;
use JIRA::Client;
use P4;
use Crypt::Rijndael;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);

$VERSION     = 1.00;
@ISA         = qw(Exporter);
@EXPORT      = ();  #list of functions that we export by default
@EXPORT_OK   = qw(ReadConfig GetP4Description CheckJiraID ProcessJiraID); #list of functions that we export on demand

%EXPORT_TAGS = ( DEFAULT => [qw(&ReadConfig)],
                ALL    => [qw(&ReadConfig &GetP4Description &CheckJiraID &ProcessJiraID)]);


sub ReadConfig {
        my ($config) = @_;
        my %userPreferences;
        open(CONFIG,"$config") or die "[ERROR] Couldn't read $config: $!";
        while (<CONFIG>) {
                chomp;  # no newline
                s/#.*//; # no comments
                s/^\s+//; # no leading white
                s/\s+$//; # no trailing white
                next unless length; # anything left ?
                my ($var, $value) = split(/\s*=\s*/, $_, 2);
                $userPreferences{$var}=$value;
        }
        return \%userPreferences;
}

sub GetP4Description {
my ($P4port,$P4user,$P4cl,$P4passwd)=@_;
my %changelistDesc;
#Establish p4 connection
my $p4 = new P4;
$p4->SetPort ( $P4port );
$p4->SetUser( $P4user );
$p4->SetPassword( $P4passwd );
$p4->Connect() or die( "Failed to connect to Perforce Server" );
#my $info = ($p4->Run("info"))[0];
#print Dumper($info);

#Get perforce description for the given changelist number
my $descCmdOut=$p4->RunDescribe( "-s", $P4cl );
#print "USER=$descCmdOut->[0]->{user}\n";
$changelistDesc{"user"}=$descCmdOut->[0]->{user};
#my $p4ChangeUser= $descCmdOut->[0]->{user};
$changelistDesc{"desc"}=$descCmdOut->[0]->{desc};
#my $desc="$descCmdOut->[0]->{desc}";
$changelistDesc{"files"}=\@{$descCmdOut->[0]->{depotFile}};
#my @files=@{$descCmdOut->[0]->{depotFile}};
return (\%changelistDesc);
}

sub CheckJiraID {
my ($jiraProjs,$desc)=@_;
my %getJiraIDs;
my (@jira_idlist,$found);
$found=0;
my @jiraProjects = split / /, $jiraProjs;
#print "desc=$desc\n";
foreach (@jiraProjects) {
        my @matches = $desc =~ /($_-\d+)/gi;
        push(@jira_idlist,@matches);
}
#print "@jira_idlist\n";
if(scalar(@jira_idlist) != 0)
{
$found=1;
}
$getJiraIDs{"found"}=$found;
$getJiraIDs{"ids"}=\@jira_idlist;
return(\%getJiraIDs);
}

sub ProcessJiraID {
        my ($jiraID,$jiraURL,$jiraLogin,$jiraPWD)=@_;
my $jiraPasswd=&hide_passwd($jiraPWD);
$jiraPasswd =~ s/\s*$//gi;
        my $jira = JIRA::Client->new("$jiraURL", "$jiraLogin", "$jiraPasswd");
        my $issue = eval { $jira->getIssue("$jiraID") };
        die "[ERROR] Jira ID $jiraID doesn't exist: Provide valid jira ID" if $@;
        my $jiraUser=$issue->{assignee};
        my $fixVer=$issue->{fixVersions}->[0]->{name};
        return($fixVer,$jiraUser);
}

sub hide_passwd(){
        my $app_secret = 'this_is_the_key_the_app_uses....';
        my $passwd_file_name = shift;
        my $passwd_file;
        # Setup the encryption system
        my $crypto = Crypt::Rijndael->new( $app_secret, Crypt::Rijndael::MODE_CBC() );

        unless ( open ( $passwd_file, '<', $passwd_file_name) ) {
                open ( $passwd_file, '>', $passwd_file_name);
                # Ask the user to enter the password the first time
                #my $password = prompt "password: ", -echo => '*'; # from IO::Prompter
                print "Enter the password";
                my $password    = <STDIN>;
                my $pass_length = 16;
                chomp($password);
                #If password is to short we complete with blank
                $password = $password." "x ($pass_length - length ( $password ) ) if ( length ( $password ) < $pass_length );
                #If password is to long we cut it
                $password = substr ( $password, 0, $pass_length ) if ( length ( $password ) > $pass_length );
                # Encrypt the password. You can save this off into a file however you need to
                my $enc_password = $crypto->encrypt($password);
                open (FH, '>', $passwd_file_name);
                print FH $enc_password;
                close FH;
        }

        #Later load it from the file and decrypt it:
        open (FH, '<', "$passwd_file_name");
        my $data=<FH>;
        close FH;
        my $newpassword = $crypto->decrypt($data);
        #$newpassword =~ s/\s*$//gi;
        #$newpassword =~ s/^\s*//gi;
        return $newpassword;
}

1;

The top level trigger script AssureJiraID.pl

cat AssureJiraID.pl
#!/usr/bin/perl -w
use strict;
use Cwd 'abs_path';
use File::Basename qw( dirname );
use lib '/export/build/p4triggers';
use Data::Dumper;
use Utilities qw(:ALL);

#Globals
my ($properties,$configFile,$P4port,$P4user,$P4cl,$P4passwd);
my $CurWD = dirname(abs_path($0));
$configFile="$CurWD/p4trigger.properties";

#Read configuration file
$properties=ReadConfig($configFile);

$P4port=$properties->{"p4port"};
$P4user=$properties->{"p4user"}; 
$P4passwd=$properties->{"p4passwd"};
$P4cl=$ARGV[0]; #%change%

#Check mandatory arguments
usage() unless $P4port;
usage() unless $P4cl;
usage() unless $P4user;

my $descRef=GetP4Description($P4port,$P4user,$P4cl,$P4passwd);
my $desc=$descRef->{"desc"};
#print "P4user = $P4user \n  desc-orig=$desc \n";
my $getJiraIDRef=CheckJiraID($properties->{jiraProjects},$desc);

if ( $getJiraIDRef->{"found"} == 0 ) {
print "[ERROR] Jira ID not provided in description \n";
exit 1;
}

foreach my $jira_id (@{$getJiraIDRef->{"ids"}}) {
my ($fix_version,$jirauser)=ProcessJiraID($jira_id,$properties->{jiraURL},$properties->{jiraLogin},$properties->{jiraPWD});
#print "Fixversion=$fix_version \nJiraUser=$jirauser\n";
}

sub usage {
print "-----------------------------------\n";
print "[ERROR] Mandatory arguments missing\n";
print "-----------------------------------\n";
print "[SYNOPSIS] $0 P4PORT P4_CHANGELIST P4USER\n";
print "[EXAMPLE]  $0 p4:1666 280459 siddesh\n"; 
print "-----------------------------------\n";
exit(1)
}

Configure p4 triggers with below info

p4 triggers

EnforceJiraID change-submit //depot/*****/... "/export/****/p4triggers/AssureJiraID.pl %changelist%"

No comments: