Pages

Wednesday, December 22, 2010

SVN Pre-commit hook failed - jira-client.py throws error

SVN Pre-commit hook failed - jira-client.py throws error

We recently upgraded our Atlassian Products (crowd, Jira, fisheye, crucible), particulary Jira from 4.0.1 to 4.2.1

Since this upgrade we could not do SVN commits. It keeps on failing and gives this message:

Problem:

svn: Commit failed (details follow):
svn: 'pre-commit' hook failed with error output:
Committer: pdhawale
Commit message: "SUITE-XXXX - Audit History changes"
Commit rejected: Unable to connect to the JIRA server at "http://xxxx.xxxxxx.co.nz".



Then I did some digging in the my SVN-server folder and found out that there is a python script for JIRA Commit Acceptance Plugin. This script gets run when we do SVN Commits. The error was thrown from this python script.

JIRA Commit Acceptance Plugin:
This plug-in lets you define certain basic rules that will determine whether a commit to your version control system will be accepted based on the issues in JIRA. For example, you can define a rule that no commit will be accepted unless it contains a valid issue key. Or you can set a rule that no commit would be accepted if the issue was not in an "open" state.
For more information go to JIRA Commit Acceptance Plugin

The python script is called jira-client.py and it is located in this location: {svn-server}\repo\hooks
In case you are using perl, The perl script is called jira-client.pl and it is located in this location: {svn-server}\repo\hooks

Solution:

JIRA Commit Acceptance plugin is not part of the Standard Jira Package. So, whenever you install or upgrade your Jira Application, you will need to explicitly (or you can say 'manually') install this plugin every time.
For more information on installation steps go to JIRA Commit Acceptance Plugin

So, the jira-client.py is one part of the JIRA Commit Acceptance plugin, The plugin adds an extra remote method that the jira-client.py script is trying to call, but because the plugin isn't installed yet, there's no remote method for the script to connect to and thus it fails and throws the error mentioned above.

You should be able to install the plugin (its free) in your JIRA server and everything should work again. You may want to double-check within JIRA that the plugin is configured properly though, as I'm not sure if the settings are kept as part of an XML backup or not.

Also, you will need to configure JIRA access and svnlookup path in the new jira-client.py for your SVN-server, as follows:

# configure JIRA access
# ("projectKey" can contain multiple comma-separated JIRA project keys like "projectKey = 'TST,ARP'".
# If you specify multiple keys, the commit will be accepted if at least one project listed accepts it.
# Or you can specify "projectKey = '*'" to force using the global commit acceptance settings if you don't
# want to specify any exact project key.)
jiraBaseURL = 'http://xxxx.xxxx.co.nz'
jiraLogin = 'xxxx'
jiraPassword = 'xxxx01'
projectKey = '*'

# configure svn lookup path
svnlookPath = 'D:\\svn-server\\bin\\svnlook.exe'



Also, please edit your new pre-commit.bat file to look at the python installation location as follows:

@c:\\Progra~2\Python25\python.exe D:\\svn-server\\repo\\hooks\\jira-client.py %1 %2



Quick Work Arround Available:

If you do not have enough time, as your Jira is already in production and people want to commit their work urgently. Then disable the SVN check on Code Check-in,  as follows:
Comment out the code in your existing jira-client.py


## invoke JIRA web service
#xmlrpcUrl = jiraBaseURL + '/rpc/xmlrpc'
#try:
#    s = xmlrpclib.ServerProxy(xmlrpcUrl)
#    acceptance, comment = s.commitacc.acceptCommit(jiraLogin, jiraPassword, committer, projectKey, commitMessage).split('|');
#except:
#    acceptance, comment = ['false', 'Unable to connect to the JIRA server at "' + jiraBaseURL + '".']

#if acceptance == 'true':
#    print >> sys.stderr, 'Commit accepted.'
#       sys.exit(0)
#else:
#    print >> sys.stderr, 'Commit rejected: ' + comment
#    sys.exit(1)



And put this line AFTER the commented lines shown above:

sys.exit(0)


This should then disable the SVN check on Code Check-in and you would be able to commit the code changes. The only problem with this quick fix is that, user is able check in the code changes without any Jira Issue key or comment.

I could not find a good solution that would tell all this to me and I had to spend one whole day to figure out what is wrong.. I hope this blog helps you and save some time for you.

Friday, December 3, 2010

java.sql.SQLException: Prepared or callable statement has more than 2000 parameter markers.

This one is pretty simple...

We use MSSQL 2005. We had a sql query as given below,

----------------------------------------------------------------------------------------------
select f from FooData f 
         where f.id = :id and f.date <= :today 
         and f.accountID in (:list)
----------------------------------------------------------------------------------------------

For one particular scenario, list was of size 2069
This crashed the sql query in run time with this error


-----------------------------------------------------------------------------------------------------------
"java.sql.SQLException: Prepared or callable statement has more than 2000 parameter markers."
-----------------------------------------------------------------------------------------------------------

If you guys don't know what this error means... and trying to find an answer on the google and various blogs...then please read on..


Interpretation
 
What this error means is that I cannot have the list of input parameters to be more than 2000. Some how you need to either split the large list into smaller ones.. or optimize your sql query. Both of these solutions are given below.

Solution 1

I had to fix this issue by partitioning the list in to small lists of size 1990 and then run the query for each of those smaller lists. Then combine the results into one list again. Now you can partition the list the way you want.. I used this implementation like below.. this uses a private class to do the partition and returns a List<List<T>>. the you can iterate through this list to run your query.

 public static <T> List<List<T>> partition(List<T> list, int size) {

        if (list == null)
            throw new NullPointerException(
                    "'list' must not be null");
        if (!(size > 0))
            throw new IllegalArgumentException(
                    "'size' must be greater than 0");

        return new Partition<T>(list, size);
    }

    private static class Partition<T> extends AbstractList<List<T>> {

        final List<T> list;
        final int size;

        Partition(List<T> list, int size) {
            this.list = list;
            this.size = size;
        }

        @Override
        public List<T> get(int index) {
            int listSize = size();
            if (listSize < 0)
                throw new IllegalArgumentException("negative size: " + listSize);
            if (index < 0)
                throw new IndexOutOfBoundsException(
                        "index " + index + " must not be negative");
            if (index >= listSize)
                throw new IndexOutOfBoundsException(
                        "index " + index + " must be less than size " + listSize);
            int start = index * size;
            int end = Math.min(start + size, list.size());
            return list.subList(start, end);
        }

        @Override
        public int size() {
            return (list.size() + size - 1) / size;
        }

        @Override
        public boolean isEmpty() {
            return list.isEmpty();
        }
    }


But this solution is slow and could take more time to load the screen results.. Therefore, you can also consider the following solution

Solution 2


The second solution is as follows. My list is actually another sql query to get account IDs. So, What I did is to use "inner joins" in my sql query to combine these two queries. This solution is much faster and cleaner. Its done as follows:


------------------------------------------------------------------------------
select f from FooData f 
         inner join FooAccount fa on f.accountID = fa.accountID
         where f.id = :id and f.date <= :today 
-------------------------------------------------------------------------------

I hope this helps you and saves your time.

Thanks for reading this post!

Tuesday, November 30, 2010

Sonar Cobertura OutOfMemory Java Heap Size

When you configure and install the Sonar for to analyze and report metrics on source code, it sets the default code coverage tool as Cobertura. The "Maximum memory to pass to JVM of Cobertura processes" is defaulted to 64m. This max memory size is often too small for running sonar on big projects which generate large metrics.

Usually, it fails in the Collection phase of Cobertura with the "OutOfMemory Java Heap size" exception.

To fix this you will need increase the maxmem for the cobertura.

If you are using the Sonar web application for doing the settings then follow these steps:
1) Go to your Sonar Web applications' home page. it will be something like http://{your sonar host url}:9000
2) Go to Configuration >> Settings >> Cobertura.
3)  put 512m in the Maxmem field
4) Save it.
5) Now you need to stop and start your Sonar server for the changes to take effect.

6) Thats it! your OutOfMemory issue should be fixed now.

If you are doing the sonar settings in the maven pom files of your project then add following to your main/parent pom file


<project>
...<build>
...</build>
<properties>
    <cobertura.maxmem>512m</cobertura.maxmem>
</properties>
</project>

If above does not work for you then try this:

<project>
   ...
  <build>
     ...
     <plugins>
       ...
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>cobertura-maven-plugin</artifactId>
         <configuration>
           <maxmem>512m</maxmem>

         </configuration>
       </plugin>
     </plugins>
   </build>
</project>

I hope this helps.