持续集成之道:在你的开源项目中使用Travis CI
持续集成之道:在你的开源项目中使用Travis CI
自从接触并践行了敏捷的一些实践之后,便深深的喜欢上了敏捷。尤其是测试自动化和持续集成这两个实践,可以显著的提高软件的质量和集成效率,实时检测项目健康度,使团队成员对项目保持充足的信心。
但是对于个人项目而言,虽然测试自动化好实现,但是要实现持续集成还是稍有难度。因为持续集成需要搭建一个集成服务器,并建立某种反馈机制。而大多数人来说并没有自己的独立服务器,并且配置也极为繁琐。
不过不用怕,现在已经进入了云时代。 Travis CI 为我们提供了免费的集成服务器,让我们省却了自己搭建集成服务器的烦恼。
Travis CI 的官网介绍是: A hosted continuous integration service for the open source community. 表明它主要是给开源社区提供持续集成服务。其与github这个全球最火爆的代码托管网站高度集成,可以很方便的为github中的项目建立持续集成服务。
它不仅支持多种语言,而且支持同时在多个运行环境中运行build,能全方位的测试你的程序。
下面就介绍下如何将 Travis CI 与自己在github上的某个repository集成。(这里以我自己的repository https://github.com/huangbowen521/SpringMessageSpike 为例。 )
首先,使Travis CI通过github OAuth认证。
点击 https://travis-ci.org/ 右上角的 Sign in with GitHub 按钮,输入自己的github账号和密码,并允许Travis CI的认证。
然后,激活GitHub Service Hook。
GitHub给用户提供了一个Service Hook接口,只要用户对host在github上的repository作用了一些action(比如push,pull),就会触发相应的Service Hook。而 Travis CI 正是基于这个原理来trigger你的build。当你发起一个push操作时,就会trigger Travis CI 的服务。
设置方法是访问 Travis CI 的 profile ,选择相应的repository打开Service Hook开关。
然后登陆你的github,访问具体的repository的Service Hook页面,确保设置了Travis CI Hook的github name和travis token。
最后,给repository配置.travis.yml文件。该文件需要放置在repository的跟目录下。
.travis.yml文件是一个相当重要的文件,里面需要配置你所使用的语言、运行环境、构建工具、构建脚本、通知方式等。最重要的是设置语言,其它的都有相应的默认值。
这是为我的 SpringMessageSpike 设置的.travis.yml文件。由于我的项目中使用了maven作为构建工具,而 Travis CI 对java语言设置的默认构建工具就是maven,所以无需在文件中显式指定。
.travis.yml
1 2 3 4 5
language : java jdk : - oraclejdk7 - openjdk7 - openjdk6
你可以使用一个travis-lint来检查你的yml文件是否是有效的。他是ruby写的一个gem,需要ruby的运行环境。安装方式是在terminal下 gem install travis-lint 。你只需要在你的repository根目录下运行 travis-lint 即可进行检查。
想要更进一步的关于.travis.yml的配置请参见: http://about.travis-ci.org/docs/user/build-configuration/
只要这三步就完成了配置。现在发起一个push就可以trigger你在 Travis CI 的build。 这时候登陆 Travis CI 可以看到你的Build的状态和日志。
你可以在respository的README.md文件中加入build状态图标。方法是在在该文件中加入 [](https://travis-ci.org/[YOUR_GITHUB_USERNAME]/[YOUR_PROJECT_NAME]) 即可。
总体来说 Travis CI 是一个轻量级、可高度定制化的免费的持续集成服务。但我觉得还是有几个缺点:
运行build需要大量的准备,耗时较长。
作为免费的服务,不支持build时间超过20分钟的项目。
主站访问速度略慢。
Table中对tr的上下拖拽移动
前天公司门户网站中新闻发布后写好的新闻想实现手动上下换位置。在网上找了一个专门为table写的js,有源码,可以自己改样式,动态效果。
正文开始:
首先需要引用一个js:
jquery
jQuery.tableDnD = { /* * Keep hold of the current table being dragged */ currentTable : null , /* * Keep hold of the current drag object if any */ dragObject: null , /* * The current mouse offset */ mouseOffset: null , /* * Remember the old value of Y so that we don't do too much processing */ oldY: 0 , /* * Actually build the structure实际构建结构 */ build: function (options) { // Set up the defaults if any this .each( function () { // This is bound to each matching table, set up the defaults and override with user options这是绑定到每个匹配表,设置默认值,并与用户选项覆盖 this .tableDnDConfig = jQuery.extend({ onDragStyle: null , onDropStyle: null , // Add in the default class for whileDragging onDragClass: "tDnD_whileDrag" , onDrop: null , onDragStart: null , scrollAmount: 5 , serializeRegexp: /[^\-]*$/, // The regular expression to use to trim row IDs serializeParamName: null , // If you want to specify another parameter name instead of the table ID dragHandle: null // If you give the name of a class here, then only Cells with this class will be draggable }, options || {}); // Now make the rows draggable jQuery.tableDnD.makeDraggable( this ); }); // Now we need to capture the mouse up and mouse move event // We can use bind so that we don't interfere with other event handlers jQuery(document) .bind( 'mousemove' , jQuery.tableDnD.mousemove) .bind( 'mouseup' , jQuery.tableDnD.mouseup); // Don't break the chain return this ; }, /* * This function makes all the rows on the table draggable apart from those marked as "NoDrag" */ makeDraggable: function (table) { var config = table.tableDnDConfig; if (table.tableDnDConfig.dragHandle) { // We only need to add the event to the specified cells var cells = jQuery("td."+ table.tableDnDConfig.dragHandle, table); cells.each( function () { // The cell is bound to "this" jQuery( this ).mousedown( function (ev) { jQuery.tableDnD.dragObject = this .parentNode; jQuery.tableDnD.currentTable = table; jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset( this , ev); if (config.onDragStart) { // Call the onDrop method if there is one config.onDragStart(table, this ); } return false ; }); }) } else { // For backwards compatibility, we add the event to the whole row var rows = jQuery("tr", table); // get all the rows as a wrapped set rows.each( function () { // Iterate through each row, the row is bound to "this" var row = jQuery( this ); if (! row.hasClass("nodrag" )) { row.mousedown( function (ev) { if (ev.target.tagName == "TD" ) { jQuery.tableDnD.dragObject = this ; jQuery.tableDnD.currentTable = table; jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset( this , ev); if (config.onDragStart) { // Call the onDrop method if there is one config.onDragStart(table, this ); } return false ; } }).css( "cursor", "move"); // Store the tableDnD object } }); } }, updateTables: function () { this .each( function () { // this is now bound to each matching table if ( this .tableDnDConfig) { jQuery.tableDnD.makeDraggable( this ); } }) }, /* * Get the mouse coordinates from the event (allowing for browser differences) */ mouseCoords: function (ev){ if (ev.pageX || ev.pageY){ return {x:ev.pageX, y:ev.pageY}; } return { x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, y:ev.clientY + document.body.scrollTop - document.body.clientTop }; }, /* * Given a target element and a mouse event, get the mouse offset from that element. To do this we need the element's position and the mouse position */ getMouseOffset: function (target, ev) { ev = ev || window.event; var docPos = this .getPosition(target); var mousePos = this .mouseCoords(ev); return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y}; }, /* * Get the position of an element by going up the DOM tree and adding up all the offsets */ getPosition: function (e){ var left = 0 ; var top = 0 ; /* * Safari fix -- thanks to Luis Chato for this! */ if (e.offsetHeight == 0 ) { /* * Safari 2 doesn't correctly grab the offsetTop of a table row this is detailed here: http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/ the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild. note that firefox will return a text node as a first child, so designing a more thorough solution may need to take that into account, for now this seems to work in firefox, safari, ie */ e = e.firstChild; // a table cell } while (e.offsetParent){ left += e.offsetLeft; top += e.offsetTop; e = e.offsetParent; } left += e.offsetLeft; top += e.offsetTop; return {x:left, y:top}; }, mousemove: function (ev) { if (jQuery.tableDnD.dragObject == null ) { return ; } var dragObj = jQuery(jQuery.tableDnD.dragObject); var config = jQuery.tableDnD.currentTable.tableDnDConfig; var mousePos = jQuery.tableDnD.mouseCoords(ev); var y = mousePos.y - jQuery.tableDnD.mouseOffset.y; // auto scroll the window var yOffset = window.pageYOffset; if (document.all) { // Windows version // yOffset=document.body.scrollTop; if ( typeof document.compatMode != 'undefined' && document.compatMode != 'BackCompat' ) { yOffset = document.documentElement.scrollTop; } else if ( typeof document.body != 'undefined' ) { yOffset = document.body.scrollTop; } } if (mousePos.y-yOffset < config.scrollAmount) { window.scrollBy( 0, - config.scrollAmount); } else { var windowHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight; if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) { window.scrollBy( 0 , config.scrollAmount); } } if (y != jQuery.tableDnD.oldY) { // work out if we're going up or down... var movingDown = y > jQuery.tableDnD.oldY; // update the old value jQuery.tableDnD.oldY = y; // update the style to show we're dragging if (config.onDragClass) { dragObj.addClass(config.onDragClass); } else { dragObj.css(config.onDragStyle); } // If we're over a row then move the dragged row to there so that the user sees the // effect dynamically var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y); if (currentRow) { // TODO worry about what happens when there are multiple TBODIES if (movingDown && jQuery.tableDnD.dragObject != currentRow) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) { jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); } } } return false ; }, /* * We're only worried about the y position really, because we can only move rows up and down */ findDropTargetRow: function (draggedRow, y) { var rows = jQuery.tableDnD.currentTable.rows; for ( var i=0; i<rows.length; i++ ) { var row = rows[i]; var rowY = this .getPosition(row).y; var rowHeight = parseInt(row.offsetHeight)/2; if (row.offsetHeight == 0 ) { rowY = this .getPosition(row.firstChild).y; rowHeight = parseInt(row.firstChild.offsetHeight)/2; } // Because we always have to insert before, we need to offset the height a bit if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) { // that's the row we're over // If it's the same as the current row, ignore it if (row == draggedRow) { return null ;} var config = jQuery.tableDnD.currentTable.tableDnDConfig; if (config.onAllowDrop) { if (config.onAllowDrop(draggedRow, row)) { return row; } else { return null ; } } else { // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) var nodrop = jQuery(row).hasClass("nodrop" ); if (! nodrop) { return row; } else { return null ; } } return row; } } return null ; }, mouseup: function (e) { if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) { var droppedRow = jQuery.tableDnD.dragObject; var config = jQuery.tableDnD.currentTable.tableDnDConfig; // If we have a dragObject, then we need to release it, // The row will already have been moved to the right place so we just reset stuff if (config.onDragClass) { jQuery(droppedRow).removeClass(config.onDragClass); } else { jQuery(droppedRow).css(config.onDropStyle); } jQuery.tableDnD.dragObject = null ; if (config.onDrop) { // Call the onDrop method if there is one config.onDrop(jQuery.tableDnD.currentTable, droppedRow); } jQuery.tableDnD.currentTable = null ; // let go of the table too } }, serialize: function () { if (jQuery.tableDnD.currentTable) { return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable); } else { return "Error: No Table id set, you need to set an id on your table and every row" ; } }, serializeTable: function (table) { var result = "" ; var tableId = table.id; var rows = table.rows; for ( var i=0; i<rows.length; i++ ) { if (result.length > 0) result += "&" ; var rowId = rows[i].id; if (rowId && rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) { rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0 ]; } result += tableId + '[]=' + rowId; } return result; }, serializeTables: function () { var result = "" ; this .each( function () { // this is now bound to each matching table result += jQuery.tableDnD.serializeTable( this ); }); return result; } } jQuery.fn.extend( { tableDnD : jQuery.tableDnD.build, tableDnDUpdate : jQuery.tableDnD.updateTables, tableDnDSerialize: jQuery.tableDnD.serializeTables } );
里面的
View Code
this .each( function () { // This is bound to each matching table, set up the defaults and override with user options这是绑定到每个匹配表,设置默认值,并与用户选项覆盖 this .tableDnDConfig = jQuery.extend({ onDragStyle: null , onDropStyle: null , // Add in the default class for whileDragging onDragClass: "tDnD_whileDrag" , onDrop: null , onDragStart: null , scrollAmount: 5 , serializeRegexp: /[^\-]*$/, // The regular expression to use to trim row IDs serializeParamName: null , // If you want to specify another parameter name instead of the table ID dragHandle: null // If you give the name of a class here, then only Cells with this class will be draggable }, options || {}); // Now make the rows draggable jQuery.tableDnD.makeDraggable( this ); });
是为控制拖拽样式,拖拽的元素的控制,里面还有好多自定义模式的自己可以看看发觉下。
源码下载: Table拖拽
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于持续集成之道:在你的开源项目中使用Travis CI的详细内容...