Earlier I had posted a VBScript version of the same integration Hook. This time I have come up with the PHP version. I know there is already a plugin available for JIRA, which does exactly the same thing. However that plugin needs to be installed on both the svn server and the JIRA server. It adds new methods to the JIRA web service.
The PHP version and the VBScript version which I presented earlier tends to be much more simpler, in that both of these hooks needs to be installed on svn server only and configuring them is a matter of changing one file, the hook script it-self. Here is the PHP code of the Hook script.
1: #!/usr/bin/php
2: <?php
3: //------------------------------------------------------------------------------
4: // A php schell script to authorize commit only if it is accompanied by a log
5: // message in <code>^([A-Z]*)\-(\d*)\s?\-\s?(.*)</code> format and that the issue
6: // id present in the log message is valid issue (Open, In Progress or Re-Opened)
7: // in JIRA and is assigned to the committer.
8: //
9: // e.g. ABC-1345 - Changed the implementation of login metod.
10: //
11: // AUTHOR : Prasad P. Khandekar
12: // CREATED: August 22, 2008
13: // VERSION: 1.0
14: //------------------------------------------------------------------------------
15: define("JIRA_SERVER", "http://<JIRA HOST>:<PORT>/JIRA/rpc/soap/jirasoapservice-v2?wsdl");
16: define("SVN_USER", "ENTER JIRA USER");
17: define("SVN_PASS", "ENTER PASSOWRD");
18: define("SVNLOOK_PATH", "/usr/bin/svnlook");
19: define("LOGMSG_REGX", "/^([A-Z]*)\-(\d*)\s?\-\s?(.*)/");
20:
21: if ($argc < 3)
22: trigger_error("Insufficient command line arguments!", E_USER_ERROR);
23:
24: $repoPath = $argv[1];
25: $txnId = $argv[2];
26:
27: $cmd = SVNLOOK_PATH . " info -r " . $txnId . " " . $repoPath;
28: //$cmd = SVNLOOK_PATH . " info -t " .$txnId . " " . $repoPath;
29:
30: $result = runCommand($cmd);
31: if (!is_array($result))
32: trigger_error("Unable to retrieve commit info for commit transaction " .
33: $txnId . " repository " . $repoPath, E_USER_ERROR);
34: if (count($result) < 4)
35: trigger_error("Log message not supplied for commit transaction " . $txnId .
36: " repository " . $repoPath, E_USER_ERROR);
37:
38: $author = $result[0];
39: $line = NULL;
40: $issueId = NULL;
41: $matches = NULL;
42: for ($cntr = 3; $cntr < count($result); $cntr++)
43: {
44: if (is_array($matches))
45: unset($matches);
46:
47: $line = $result[$cntr];
48: if (preg_match(LOGMSG_REGX, $line, $matches))
49: {
50: $issueId = $matches[1] . "-" . $matches[2];
51: break 1;
52: }
53: }
54: if (!isset($issueId) || is_null($issueId))
55: trigger_error("Unable to retrieve JIRA issue id for commit transaction " .
56: $txnId, E_USER_ERROR);
57:
58: if (!acceptCommit($author, $issueId))
59: trigger_error($author . " is not allowed to commit against issue (" .
60: $issueId . ")!", E_USER_ERROR);
61: else
62: exit(0);
63:
64: //------------------------------------------------------------------------------
65: // HELPER Functions
66: //------------------------------------------------------------------------------
67: /**
68: * Function acceptCommit calls the JIRA web service and checks following conditions
69: * 1. The Issue id represents a valid JIRA issue with one of the following status
70: * 1. Open
71: * 2. In Progress
72: * 3. Re-Opened
73: * 2. The issue is assigned to the committer.
74: *
75: * If both of these conditions are met then the commit is allowed.
76: * @param string - the user id of the committer.
77: * @param string - The JIRA issue id used in the commit log message.
78:
79: * @return boolean
80: */
81: function acceptCommit($pAuthor, $pIssueId)
82: {
83: $client = new SoapClient(JIRA_SERVER);
84: $authId = $client->login(SVN_USER, SVN_PASS);
85: if (is_soap_fault($authId))
86: trigger_error("JIRA Authentication failed!", E_USER_ERROR);
87:
88: $issue = $client->getIssue($authId, $pIssueId);
89: if (is_soap_fault($issue))
90: trigger_error("Usnable to retrieve details for issue " . $issueId,
91: E_USER_ERROR);
92:
93: $status = intval($issue->status);
94: $author = $issue->assignee;
95: if (($status == 1 || $status == 3 || $status == 5) &&
96: strcasecmp($author, $pAuthor))
97: return true;
98:
99: return false;
100: }
101:
102: /**
103: * Function runCommand is used to launch a external program and capture it's
104: * output.
105: * @param string The shell command to be launched.
106: * @param boolean A flag which allows running shell commands which do not return
107: * anything.
108: * @return array
109: */
110: function runCommand($cmd, $mayReturnNothing = false)
111: {
112: $output = array ();
113: $err = false;
114:
115: $c = quoteCommand($cmd);
116:
117: $descriptorspec = array (0 => array('pipe', 'r'),
118: 1 => array('pipe', 'w'),
119: 2 => array('pipe', 'w'));
120:
121: $resource = proc_open($c, $descriptorspec, $pipes);
122: $error = "";
123:
124: if (!is_resource($resource))
125: trigger_error("BADCMD : " . $cmd, E_USER_ERROR);
126:
127: $handle = $pipes[1];
128: $firstline = true;
129: while (!feof($handle))
130: {
131: $line = trim(fgets($handle));
132: if ($firstline && empty($line) && !$mayReturnNothing)
133: {
134: $err = true;
135: }
136:
137: $firstline = false;
138: if (!empty($line))
139: $output[] = $line;
140: }
141:
142: while (!feof($pipes[2]))
143: {
144: $error .= fgets($pipes[2]);
145: }
146:
147: $error = trim($error);
148:
149: fclose($pipes[0]);
150: fclose($pipes[1]);
151: fclose($pipes[2]);
152:
153: proc_close($resource);
154:
155: if (!$err)
156: return $output;
157: else
158: trigger_error($error, E_USER_ERROR);
159: }
160:
161: /**
162: * On windows you are required to enclose the command in double quotes to
163: * avoid the problems that may occure due to long file or path names.
164: * @param string The command to be enclosed in quotes.
165: * @return string
166:
167: */
168: function quoteCommand($cmd)
169: {
170: $osName = strtoupper(php_uname('s'));
171: // On Windows machines, the whole line needs quotes round it so that it's
172: // passed to cmd.exe correctly
173: if (stripos($osName, "WINDOWS") !== false)
174: $cmd = "\"$cmd\"";
175:
176: return $cmd;
177: }
178: ?>
179: