持续集成之道:在你的开源项目中使用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 CIprofile,选择相应的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状态图标。方法是在在该文件中加入 [![Build Status](https://travis-ci.org/[YOUR_GITHUB_USERNAME]/[YOUR_PROJECT_NAME].png)](https://travis-ci.org/[YOUR_GITHUB_USERNAME]/[YOUR_PROJECT_NAME])即可。

 

 

总体来说Travis CI是一个轻量级、可高度定制化的免费的持续集成服务。但我觉得还是有几个缺点:

 

  1. 运行build需要大量的准备,耗时较长。

  2. 作为免费的服务,不支持build时间超过20分钟的项目。

  3. 主站访问速度略慢。

    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拖拽

原文地址:https://www.cnblogs.com/Leo_wl/p/3108739.html