最近使用CI Server, 像hudson, cruisecontrol, luntbuild. 三者Luntbuild功能最全面, 当然crusecontrol,hudson也有丰富的plugin得到增强.
下载luntbuild1.6.2, 发现Luntbuild没有直接支持从版本管理工具中获取Revision来生成Build Version. Build Version可以使用OGNL来生成, 翻阅用户手册得知, 其OGNL的Root Object为Schedule, 决定改源码达到此功能.
学习了Ognl后并仔细阅读源码发现, com.luntsys.luntbuild.builders.Builder.Schedule具有sytem属性,指向OgnlHelper.决定改写此类.
为com.luntsys.luntbuild.utility.OgnlHelper添加方法
public String retrieveSvnHeadRevision(SvnAdaptor vcs);
这样Ognl Expression可以写成:
${system.retrieveSvnHeadRevision(project.vcsList[0])}
由于一般项目只采用Single VCS, project.vcsList[0]获取第一个VCS便可.
参考 com.luntsys.luntbuild.vcs.SvnAdaptor 方法源码 getRevisionsSince(...), 便可实现自己的retrieveSvnHeadRevision
public Revisions getRevisionsSince(Date sinceDate, Schedule workingSchedule, Project antProject) { //... }
实现过程遇到私有方法访问问题, 没发现luntbuild有生成相关的Error Log, 觉得luntbuild这点有待改进.
代码改写如下, 与SVN Repos Sever的交互利用了SvnKit. 详情可看http://svnkit.com/javadoc/index.html
try { svnClientManager = SVNClientManager.newInstance( SVNWCUtil.createDefaultOptions(true), vcs.getUser(), vcs.getPassword()); SVNLogClient svnLogClient = svnClientManager.getLogClient(); SvnModule module = (SvnModule) vcs.getModules().get(0); SVNURL url = (SVNURL)invokeSvnAapator(vcs, "getModuleUrl", new Class[]{SvnModule.class}, new Object[]{module}); final SvnRevsionHolder svnRevsionHolder = new SvnRevsionHolder(); svnLogClient.doLog(url, null, SVNRevision.HEAD, SVNRevision.HEAD, SVNRevision.HEAD, false, true, 1, new ISVNLogEntryHandler() { public void handleLogEntry(SVNLogEntry svnLogEntry) throws SVNException { svnRevsionHolder.setRevision( String.valueOf(svnLogEntry.getRevision())); svnRevsionHolder.setLastCommittedDate(svnLogEntry.getDate()); } }); return svnRevsionHolder.toBuildVersion(); } catch (Exception e) { throw new IllegalStateException("failed to retrieve svn revison", e); } finally { if (svnClientManager != null) { svnClientManager.dispose(); } }
调用私有方法getModuleUrl(...)获取path
protected Object invokeSvnAapator(SvnAdaptor vcs, String methodName, Class[] methodParams, Object[] args) { Method method = null; try { method = SvnAdaptor.class.getDeclaredMethod(methodName, methodParams); method.setAccessible(true); return method.invoke(vcs, args); } catch (Exception e) { throw new IllegalStateException("Failed to invoke method [" + methodName + "] on SvnAdaptor", e); } }
SvnKit的API采用回调实现处理,另外定义了内部类来存储返回信息
private static class SvnRevsionHolder { private String revision; private Date lastCommittedDate; public void setLastCommittedDate(Date lastCommittedDate) { this.lastCommittedDate = lastCommittedDate; } public void setRevision(String revision) { this.revision = revision; } public String toBuildVersion() { return new StringBuffer() .append(revision) .append("-") .append( new SimpleDateFormat("yyyyMMddHHmm").format(lastCommittedDate) ) .toString(); } }
编译之后把原有的class文件替换后,重启Server便大功告成.