七夕

2014年七夕

2014-8-4

仿佛生日是七夕,

或是嫦娥或织女。

牛郎总入桂下梦,

吴刚常在河外堤。

越女吴山情脉脉,

楚天湘水人依依。

人间节日尽繁华,

都是天外星斗移。

2012年七夕

2012-08-24

依稀景物依稀梦,

恍惚人事恍惚情。

从前多少悲欢事,

都在今日明月中。

2011年七夕

2011-08-06

神交隔万里,

意会越千年。

今日上弦月,

为谁照窗前?

假日

2009-08-26

夜夜牛郎奉春色,

岁岁银河绕广寒。

七夕云雨逐流下,

追得神女到巫山。

七夕-雕塑园

2007-08-18

熙熙人如织,

淡淡晚云愁。

明日鹊桥会,

银河月似钩。

CentOS下安装git和配置git服务器

在远程仓库一节中,我们讲了远程仓库实际上和本地仓库没啥不同,纯粹为了7x24小时开机并交换大家的修改。

GitHub就是一个免费托管开源代码的远程仓库。但是对于某些视源代码如生命的商业公司来说,既不想公开源代码,又舍不得给GitHub交保护费,那就只能自己搭建一台Git服务器作为私有仓库使用。

搭建Git服务器需要准备一台运行Linux的机器,强烈推荐用Ubuntu或CentOS,这样,通过几条简单的apt或yum命令就可以完成安装。

假设你已经有sudo权限的用户账号,下面,正式开始安装。

第一步,安装git:

yum install curl curl-devel zlib-devel openssl-devel perl cpio expat-devel gettext-devel

下载最新的git包

wget http://www.codemonkey.org.uk/projects/git-snapshots/git/git-latest.tar.gz
tar xzvf git-latest.tar.gz
cd git-2011-11-30 #你的目录可能不是这个
autoconf
./configure --prefix=/usr/local/git
make
make install

检查下安装的版本,大功告成

git --version

第二步,创建一个git用户,用来运行git服务:

$ sudo adduser git
$ git config --global user.name "whdsmile"
$ git config --global user.email "whdsmile@gmail.com"

第三步,创建证书登录:

收集所有需要登录的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。

第四步,初始化Git仓库:

先选定一个目录作为Git仓库,假定是/srv/sample.git,在/srv目录下输入命令:

$ sudo git init --bare sample.git

Git就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常都以.git结尾。然后,把owner改为git:

$ sudo chown -R git:git sample.git

第五步,禁用shell登录:

出于安全考虑,第二步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成。找到类似下面的一行:

git:x:1001:1001:,,,:/home/git:/bin/bash
改为:
git:x:1001:1001:,,,:/home/git:/usr/local/git/bin/git-shell

这样,git用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。

第六步,在/srv/sample.git目录下,假设有一个test目录:

$ git add test
$ git commit -m "add file"

第七步,在开发机上克隆远程仓库:

现在,可以通过git clone命令克隆远程仓库了,在各自的电脑上运行:

$ git clone git@server:/srv/sample.git

Cloning into 'sample'...
warning: You appear to have cloned an empty repository.

剩下的推送就简单了。

管理公钥

如果团队很小,把每个人的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys文件里就是可行的。如果团队有几百号人,就没法这么玩了,这时,可以用Gitosis来管理公钥。

这里我们不介绍怎么玩Gitosis了,几百号人的团队基本都在500强了,相信找个高水平的Linux管理员问题不大。

参考资料

学习OpenX广告管理与跟踪系统

OpenX Ad Server (简称OpenX )是一个采用PHP开发的广告管理与跟踪系统。

安装和部署

配置要求

  1. 支持PHP
  2. 支持MySql

下载源代码

http://www.openxconsultant.com/blog/2013/08/openx-source-v2-8-11-released-for-download/下载源代码,或者先从http://www.openxconsultant.com/blog/category/featured/检查最新发布。

提示:如果研究学习源代码,可以使用SVN检出,地址:https://svn.openx.org/openx/tags/2.8/openx-2.8.11/

安装部署

  1. 将下载的源代码命名为“openx”,上传到WEB服务器的根目录下。
  2. 给var、plugins、www/admin/plugins、/www/images子目录赋予写权限。
  3. 在浏览器中访问http://{yourdomain}/openx,进入到OpenX的安装界面。
  4. 根据提示信息设置数据库配置和管理员配置。

提示:选择中文简体,会出现一些乱码问题,建议采用命名和语言版本均以英文为主。时区可以选择Asia/Shanghai。

基本的操作和使用

基础概念

  1. Advertisers:广告主
  2. Campaigns:广告活动
  3. Banners:广告
  4. Websites:网站
  5. Zones:广告位
  6. Targeting Channels:目标频道

基本操作步骤

  1. 添加广告主。例如:京东商城
  2. 为广告主添加广告活动。例如:节日大促
  3. 添加广告。例如:广告 980 X 90
  4. 添加网站。例如:http://www.uuu.com
  5. 添加广告位。例如:广告位 980 X 90
  6. 链接广告到广告位
  7. 复制广告位代码到网站

添加广告主

登录系统后,进入Inventory > Advertisers。

选择添加新广告主(Add new advertiser),进入添加新广告主界面。

填写广告主的基本信息(Basic information):

  • 名称(Name): 广告主名称必须唯一,广告主名称不能相同。 这里我们写“京东商城”
  • 联系人(Contact): 联系人将被用在所有给广告主的邮件里。
  • 邮箱(Email): 必填项,广告主的邮箱

在广告主报告(Advertiser report)区域,选择什么条件以及什么时间下需要给广告主发邮件:

  • 当广告计划自动生效或者失效的时候发邮件(Email when a campaign is automatically activated/deactivated):OpenX会在广告计划生效或者失效的时候给广告主发邮件提醒。如果你不想发送此提醒,可以不选此框。
  • 广告计划投放报告邮件(Email campaign delivery reports): 当您想日常性的给广告主发送报告的时候选择此选择框。默认的设置是每周发送报告给广告主。如果您想修改发送报告的周期(Number of days between campaign delivery reports),只要简单的修改下周期即可。如果您给广告主提供的访问系统的帐号,则不建议发送邮件报告。

其他(Miscellaneous)区域可以让您设置广告投放的限制选项:

  • 在一个页面只显示此广告主的一个广告(Display only one banner from this advertiser on a web page): 限制广告在一个页面上只显示一次。
  • 备注(Comments): 广告主的备注信息。

添加广告活动

完成广告主(京东商城)创建后,从广告主界面点击添加新广告活动(Add new campaign),系统将会带您到添加新广告活动的界面。

填写基本信息(Basic information):

  • 名称(Name):广告活动名称
  • 广告活动的类型(Campaign type):

下一步是选择广告活动的类型。有三种活动类型可选:

  1. 合约型(排期):Contract: 合约型广告计划将会在预订的时间和显示次数内投放。
  2. 合约型(买断):Contract (Exclusive): 买断式的广告计划将会占用所有的显示资源,并且优先级高于所有其他广告计划。
  3. 剩余抄底:Remnant: 标准的广告计划类型,可以基于特殊的投放限制及时期来进行投放。

选择好广告计划类型后,可以设置一些其他的内容:

  • 日期:Date: 输入广告计划的开始和结束日期。
  • 计费模式:Pricing: 允许您设置广告计划的计费模式(CPM、CPC、APC),费率和展示次数。
  • 广告计划优先级:Priority in relation to other campaigns: 默认的优先级为5. 优先级设置级别在1到10之间(10代表优先级最高),如果需要的话,可以设置每天投放的PV/Click或者转换的限额Set
  • 用户投放频次:Delivery capping per visitor: 此处可以设置总共以及每用户显示的限额次数。
  • 其他:Miscellaneous: 如果希望隐藏与此广告计划关联的广告主和网站,可以进行设置。另外,也可以设置竞争机制,如果设置了竞争机制,则OpenX在显示的时候投放该计划下所有的广告。

设置完成后,点击保存。

添加广告

  1. 点击添加广告(Add new banner)链接。
  2. 选择广告的类型(Please choose the type of the banner)。默认为上传本地广告物料文件到Web服务器(Upload a local banner to the webserver)。
  3. 填写广告名字(如广告 980 X 90)
  4. 上传图片

广告类型

  1. 使用Web服务器的本地广告 这是使用最广泛的广告类型。它用于图像广告包括JPG,GIF和PNG文件。广告上传到OpenX的广告服务器并存储在文件系统中的一个文件夹。安装系统时,默认图片文件上传到www/images/,并生生一个随机字符串文件名的文件。
  2. 使用SQL的本地广告 是把广告图保存在,在数据库中的二进制数据,而不是存储在一个文件夹。
  3. 通用的HTML广告 这可能是一个HTML网页的形式,多张图片,表格,JavaScript文件。
  4. 通用文本横幅 适用于任何拟作为纯文本显示。简单的文本链接是受欢迎的用法。此外,也可以写长段的文本作为广告。
  5. 外部广告(即url图片地址)

添加网站

进入Inventory > Websites,在网站管理界面,在右上方选择添加新网站(Add new website),您将可以看到添加新网站界面。

创建新网站:

  • 网站URL(Website URL): 输入您网站的URL。
  • 网站名(Name):输入网站名称。此名称将会显示在网站列表界面,注意网站名必须唯一。
  • 联系人(Contact):输入网站联系人。
  • Email: 输入网站管理员的Email地址。
  • 类目(Category):在下拉列表里选择网站的类目。
  • 国家/语言(Country/Language): 在下拉列表中选择相关的国家和语言。

完成以上操作后点击保存,添加网站成功。

添加广告位

进入Inventory > Zones,点击添加新广告位(Add new zone)选项,到达添加新广告位页面。

添加新广告位:

  • 名称(Name): 广告位名称必须唯一。如果此项为空,OpenX默认会设置一个名称,默认的是网站名称后面加上“-default”。
  • 描述(Description):输入广告位的相关信息。如广告位 980 X 90
  • 行业分类(Category):
  • 类型(Zone type):选择广告位类型(本指南有专门的页面解释各种广告位类型)
  • 尺寸(Size):必须为每个广告位选择尺寸(除了文字广告位之外),只有符合尺寸的广告创意才会在此广告位显示。下拉列表里面的尺寸都是IAB定义的标准尺寸,也可以设置自定义的尺寸。
  • 备注(Comments):广告位备注

一旦完成操作点击保存,完成添加广告位。

广告位类型

  1. 旗帜,按钮,或矩形:这是使用最广泛的广告位类型,可以显示包括图像在内的任何有创意的类型 JAVASCRIPT,HTML,等等。
  2. 浮动广告 此广告位类型是用来显示浮动或弹出的横幅上,如出现网络浏览器的动态行为 消失了一段时间后,移动光标,等等。
  3. 文字广告 你想要您的网站上卖文本连接,你应该使用这种类型
  4. 电子邮件/邮件列表版位 如果你想给你的网站用户发送电子邮件和简讯,使用此广告位,可以在电子邮件中嵌入广告横幅。

链接广告到广告位

在广告位列表中,点击链接广告(Linked Banners),选择一个广告主和广告活动。

或者在广告的详细页面的链接广告位(Linked Zones)标签中,选择一个广告位。

复制代码到网站

在广告位列表中,点击获取代码(Invocation Code)

Openx 账户类型

用户有一个用户名和密码,与至少一个OpenX帐户,并可以与任意数量的账户挂钩。一个用户可以有不同的连结多种帐户的多个角色。每个角色都有其自己的设置权限,定义用户可以执行相关联的帐户上的行动。

角色和权限

系统安装后的初始用户即是管理员,又是经理。

进入广告主,或网站的详情编辑页面,点击用户访问(User Access)标签,在操作(Actions)下拉菜单中,可以创建或关联使用该账户访问的用户。

管理员(Administrator)####

  • 创建经理帐户
  • 将用户添加到经理帐户
  • 可以作为一个经理
  • 创建其他管理员用户
  • 查看主页和用户日志页
  • 管理全球和维护设置
  • 直接选择

经理(Manager)

  • 创建和管理广告商和网站
  • 添加其他的经理帐户
  • 将用户添加到广告商和网站
  • 查看主页和用户日志页
  • 管理帐户偏好
  • 渠道管理

网站(Website)

  • 创建区域
  • 横幅链接到区域
  • 生成调用代码
  • 链接此帐户的其他用户

广告主(Advertiser)

  • 查看广告活动
  • 修改广告信息
  • 激活广告活动
  • 停用广告活动
  • 链接此帐户的其他用户

参考资料

GitLab和TortoiseGit、msysGit的配合使用

软件安装

下载和安装windows下Git环境:

  1. TortoiseGit(https://tortoisegit.org/),是 TortoiseSVN 的 Git 变种,主要用于图形化显示。
  2. msysGit(https://gitforwindows.org/),windows 下的Git 版本,是 TortoiseGit 所必须依赖的。

下载完两个软件之后,首先安装 TortoiseGit,安装完 TortoiseGit 之后先别急着用,接着安装 msysGit,安装过程中的一些选项都可以默认!

SSH密钥和Git Bash

本节介绍在 Git 命令行(Git Bash)中 SSH 密钥的生成,以及在 Gitlab 上的使用。

使用命令行进行 Git 操作,显得高端、大气、上档次。如果你不慕虚名,只想生活简单而美好,就像使用 SVN 小乌龟(TortoiseSVN)那样工作,可以直接跳过本节。

生成SSH密钥

  1. 检查当前用户目录中有没有 .ssh 目录。如果没有的话,在命令行中使用 mkdir .ssh 创建。
  2. 安装 Git 后,进入某个目录,使用右键菜单打开 “Git Bash”。
  3. 键入命令:ssh-keygen -t rsa -C "your email"。邮件地址可以不写,默认是 本机用户名@本机机器名 。最好是填写一些标识自己的记号。
  4. 提醒你输入 key 的名称,输入 id_rsa。注意: id_rsa 名字是固定的,因为 GitLab 只认识这个。
  5. 提醒你输入 key 的密码,空白即可。
  6. 在当前目录下产生两个密钥文件:id_rsa 和 id_rsa.pub
  7. 把生成的密钥文件复制到当前用户的 .ssh 目录下。

在 Gitlab 上添加公钥

用记事本打开、复制 id_rsa.pub 文件的内容,在 Gitlab 网站 My Porfile 页面右下角,点击 Add Public Key ,粘贴刚才复制的内容到 Key 的大文本框,提交即可。

注意:在复制内容的时候,文本的两端都不要有空格和换行。

在命令行中进行Git操作

从程序目录打开 “Git Bash”(或使用右键菜单),在命令行中git clone一个项目。

提示是否把项目Git库的域名设置为可信任的已知域名,直接回答yes就可以了。

其他命令,一样的用法。不清楚的话,可以查阅《史上最浅显易懂的Git教程》。

TortoiseGit中的密钥

本节介绍在Git小乌龟(TortoiseGit)中生成密钥,以及在Gitlab上的使用。

生成密钥

  1. 在开始菜单->TortoiseGit->Puttygen。这是一个用于TortoiseGit的Putty密钥生成器。
  2. 点击 generate 按钮。让鼠标在 generate 按钮以上、进度条以下的空白区域随机晃动,直到密钥生成完毕。
  3. 复制粘贴空白区域生成的SSH密钥文本(ssh-rsa。。。),在Gitlab网站My Porfile页面右下角,点击 Add Public Key ,粘贴刚才复制的内容到Key的大文本框,提交即可。注意:在复制内容的时候,文本的两端都不要有空格和换行。Title文本框随便写一些内容就可以,主要是区别不同的Key,没有特别的用途。
  4. 点击 save private key 按钮,把文件生成在当前用户目录下的.ssh目录中(生成的文件后缀是.ppk)。

使用右键菜单

  1. 在打算git clone项目的目录中,右键选择Git克隆
  2. 勾选 加载putty密钥 ,并选择上面生成的后缀是.ppk的私钥文件。
  3. 后续的操作,及除git clone以外的工作,就不需赘述了。

参考资料

Yeoman的安装和使用

安装步骤

本教程的内容较少原创,多从其他文档上摘录。

Yeoman 1.0 包含以下三套工具,分別說明如下:

  • yo - the scaffolding tool from Yeoman ( 用來自動產生網站骨架或程式碼的工具 )
  • bower - the package management tool ( 用來管理特定網站下所使用的各式前端套件,如: jQuery )
  • grunt - the build tool ( 用來執行一些網站的自動化工作,例如單元測試、最小化、執行批次命令 )

要安裝這三套工具之前,還有許多相依的工具必須事先安裝,否則工具指令會無法正確執行,以下包括 node.js , Git for Windows 與 RubyInstaller 這三套工具的安裝注意事項:

安裝 node.js for Windows

请选择正確的 Windows 安裝包,注意 CPU 架構有区分 32-bit 与 64-bit 两种:

node安装包

安裝时要确保 Add to PATH 項目有被安装进去:

node安装

安裝 Git for Windows 工具

安裝到 Adjusting your PATH environment 步骤時,选择 Run Git from the Windows Command Prompt 的相容性比较高,问题也会少很多:

git安装

其他保留预设值即可。

安装 Ruby 执行环境

由於前端开发作业经常会用到 Compass 工具撰写 CSS,而且在使用 Yeoman 的時候,有些产生器所产生的 grunt 定义包也会用到 Compass 来执行,所以可以预先安装好。

安裝 Compass 工具会需要先安裝 Ruby 才能安装与使用。建议通过 RubyInstaller (Windows) 提供的 MSI 安装包进行安裝,但安裝的过程中有一個步驟非常重要,你必須在 Installation Destination and Optional Tasks 步驟時,勾选 Add Ruby executables to your PATH 选项才行,如下图示:

ruby安装

安裝好这些工具之后,就可以开始准备安裝 Yeoman 相关工具了:

  1. 打开命令行。

  2. 使用npm 安裝 yo , bower 與 grunt 工具。

     npm install -g yo grunt-cli bower
    

    其中 -g 代表要把 yo , grunt-cli , bower 這三个套件安裝到全域 (global)

    yo安装

  3. 安裝 yo 相关的 程序码产生器 (generator) 套件

    因為 yo 這套工具主要就是用來自動產生網站骨架或程式碼,在執行 yo 之前,你必須預先安裝好這些程式碼產生器範本,這些被稱為 YEOMAN GENERATORS,你可以在 YEOMAN GENERATORS 找到許多現成的產生器範本,並且一樣透過 npm 進行安裝。

    例如你在 YEOMAN GENERATORS 頁面找到一個 webapp 產生器,那麼你可以用以下指令進行安裝:

     npm install -g generator-webapp
    

    如果想安裝 angular 產生器,那麼你可以用以下指令進行安裝:

     npm install -g generator-angular
    

    以此類推!

  4. 如果你要順道安裝 Compass 的話,也可以輸入以下指令進行安裝

     gem update --system
     gem install compass
    

    Yeoman 與 Compass 安裝完成!

Yeoman 的使用

  1. 先创建一个网站目录,例如webapp。

  2. 在这个目录下,命令行执行命令,产生网站骨架:

  3. yo angular

    这是一個交互的过程,yo安装哪些模块:

    创建网站
    安装完成后可能会遇到一些问题,如:
    创建网站
    表示依赖的模块需要手动bower install & npm install安装。

语义化版本控制 2.0.0

译者注1:Semantic Versioning 2.0.0的原文地址是http://semver.org

概要

版本号MAJOR.MINOR.PATCH(主版本号.副版本号.补丁版本号)的递增规则如下:

  1. 当以不向后兼容的方式,变更API时,递增主版本号。
  2. 当以向后兼容的方式,增加功能时,递增副版本号。
  3. 当以向后兼容的方式,修正BUG时,递增补丁版本号。

预发布信息和构建元数据可以作为附加标签,扩展MAJOR.MINOR.PATCH(主版本号.副版本号.补丁版本号)的格式。

引言

在软件开发管理的世界里,有一个可怕的地方叫做“依赖关系地狱”。当你的系统越来越大,集成了更多的包,你就会深刻的认识到自己的卑微和渺小。直到有一天,你在这个坑里彻底绝望。

系统依赖的模块发布新版本,就成了噩梦。如果依赖关系的规定过于严格,会遇到一个版本依赖关系的死结(升级一个依赖包之前,必须升级完所有的依赖包)。如果依赖关系规定的太松散,版本依赖关系的混乱就会成为你的切肤之痛(假定你的版本兼容性很重要)。当版本依赖关系的死结、混乱,让你不能轻松、安全的向前迁移项目的时,你就坠入了“依赖关系地狱”。

为了解决这个问题,我提出了一套简单的规则和要求,决定版本号如何分配和递增。这些规则都是基于(但不限于)业界早已存在的流行做法。使用此制度的软件必须声明一个公共API,可以在代码内部声明,也可以严格地写入文档中,但必须是清晰而准确的。一旦确定了公共API,都必须通过明确的版本号递增,来表明系统所做的变更。认真考虑一下X.Y.Z(主版本号.副版本号.补丁版本号)的版本格式。不影响API的BUG修正,递增补丁版本号。向后兼容API的功能新增或变更,递增副版本号。不向后兼容的API变更,递增主版本号。

我把这个制度称为“语义化版本控制”。在这个方案中,规范了从一个版本到下一个版本的版本号,规范了更改版本号传达源代码意图的方法,以及源代码做了什么样的修改。

语义化版本控制规范(SemVer)

在本文档中,对关键词(”MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL”)的使用,遵循RFC2119标准的规范。

译者注2:RFC2119标准规范了表示“要求”(Requirement)的动词涵义。关于RFC2119标准可以参考《RFC2119 中文版-RFC文档用于指出要求级别的关键字》。

  1. 使用语义化版本控制的软件必须(MUST)声明一个公共的API。这个API可以在源代码的内部声明,也可以在文档中严格的定义。无论怎么做,都应该是清晰而全面的。
  2. 一个标准的版本号必须(MUST)是X.Y.Z的形式。其中的X、Y和Z都要是正整数,并且禁止(MUST NOT)包含前导零。X是主版本号,Y是副版本号,Z是补丁版本号。每个元素数字的递增,必须(MUST)是1。例如:1.9.0 -> 1.10.0 -> 1.110
  3. 一旦发布一个包的版本,该版本的内容禁止(MUST NOT)再做任何修改。任何的修改都必须(MUST)发布一个新的版本。
  4. 主版本0(0.y.z)用于初始开发。此时的公共API随时都可能会改动,是不稳定的。
  5. 在1.0.0版本中,公共API作出正式的定义。后续的版本号变更,都决定于公共API是否变更,以及如何变更。
  6. 以向后兼容的方式修正BUG时,必须(MUST)递增补丁版本号Z(x.y.Z | x > 0)。BUG修正的定义,是在源代码内部修正错误的行为。
  7. 当以向后兼容的方式变更公共API时,或者公共API中原有的功能标记为“不建议使用(deprecated)”时,必须(MUST)递增副版本号Y(x.Y.z | x > 0 )。源代码内部大量增加、修改功能时,也可以(MAY)递增副版本号。副版本号的递增可以(MAY)包括补丁版本的更新内容。副版本号递增后,补丁版本号必须(MUST)重置为0。
  8. 当以不向后兼容性的方式,变更公共API时,必须(MUST)递增主版本号X(X.y.z | X > 0),可以(MAY)包含副版本和补丁版本级别的变更。主版本递增后,副版本号和补丁版本号必须(MUST)重置为0。
  9. 预发布的版本号,可以(MAY)在补丁版本号后面,添加一个破折号和一系列被点分割的标识符。这些标识符必须(MUST)由ASCII码中的字母和数字以及连字符[0-9A-Za-z-]组成。标识符禁止(MUST NOT)为空。数字禁止(MUST NOT)包含前导0。预发布版本号的优先级比正常的版本号低。预发布版本号表示该版本是不稳定的,可能无法达到其指明的正常版本号的兼容性预期。例如:1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92
  10. 构建的元数据,可以(MAY)在补丁版本号或预发布版本号后面,添加一个加号和一系列由连字符分隔的标示符组成。这些标识符必须(MUST)由ASCII码中的字母和数字以及连字符[0-9A-Za-z-]组成。标识符禁止(MUST NOT)为空。在确定版本号的优先级时,构建元数据应该(SHOULD)被忽略。因此,如果两个版本号的差异,仅仅在于构建元数据,就视为具有相同的优先级。例如:1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85
  11. 优先级是指在排序时,版本号之间如何进行比较。优先级必须(MUST)是,根据版本号按照主版本号、副版本号、补丁版本号和预发布标识的顺序进行计算产生的(构建元数据不参与优先级的比较)。优先级总是从左到右的,依次比较主版本号、副版本号、补丁版本号的数字大小。例如:1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。在主版本号、副版本号、补丁版本号都相同时,预发布版本号的优先级低于正常版本号。例如:1.0.0-alpha < 1.0.0。两个预发布版本号的主版本号、副版本号、补丁版本号都相同时,优先级必须(MUST)从左至右的比较由点分隔的标识符,直到发现差异。标识符仅由数字组成的,比较数字的大小。标识符包含字母或连字符的,按照ASCII码的顺序进行比较。数字标识符总是小于非数字标识符。如果前面所有的标识符都是相同的,版本号中预发布字段较长的,优先级较高。例如:1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0

为什么要使用语义化版本控制

语义化版本控制并不新鲜,也不是一个革命性的想法。事实上,你可能做了很多,已经完成了这件事。问题是完成并不等于极致。如果不符合某种正式的规范,版本号在依赖关系管理上基本没有什么用处。给上述想法起个名字,做出清晰的定义,就很容易向软件用户传达你的意图。一旦这些意图是明确的,一个灵活的(但也不能太灵活)依赖关系管理规范,就流畅的运转起来了。

举一个简单的例子,说明语义化版本控制如何把你从“依赖关系地狱”中拯救出来。设想一个叫“消防车”的库,依赖一个使用语义化版本控制的包,名叫“梯子”。“消防车”刚刚生产出来的时候,梯子的版本号是3.1.0。由于“消防车”使用了在3.1.0版本才开始提供的一些功能,你就可以放心地指定依赖的“梯子”的版本大于等于3.1.0,但低于4.0.0。现在,当“梯子”有3.1.1和3.2.0的版本可用时,就可以更新到你的包管理系统,并知道他们将与当前依赖的软件兼容。

作为一个负责任开发者,你当然会验证任何包所标榜的新功能。现实世界可是一个鱼龙混杂的地方,做什么事情都可以,但要警惕。你可以让语义化版本控制,给你提供一个稳健的方式来发布和升级包,不必再被迫为使用依赖包的新版本而反复折腾,为你节省时间,减少麻烦。

如果这一切听起来还不错,你需要做的所有事情,就是开始声明你正在使用语义化版本控制,并遵循其规则。欢迎你在README文档中链接这个网站(译者注3),让更多的人知道这个规则,并从中受益。

译者注3:原文中提到的网站是指http://semver.org

常见问题

在0.y.z的初始开发阶段,我应该怎么处理我的修订?

最简单的做法就是从0.1.0版本开始你的初始开发,在后续的发布中递增副版本号。

我怎么知道什么时候发布1.0.0版本?

如果你的软件在产品环境中使用,它可能已经应该是1.0.0。如果的软件用户,已经开始依赖一个稳定的API,应该是1.0.0。如果你担心很多向后兼容的问题,应该已经是1.0.0。

这难道不会妨碍快速开发和快速迭代吗?

所有在快速开发和快速迭代的时候,主版本号都是0。如果你的API每天都在改变,仍然应该会在版本0.y.z阶段。或者,在一个单独的开发分支中,开展下一个主版本的开发工作。

公共API如果连最微小的向后不兼容的改变,都需要一个主版本号的冲击,会不会太迅速的就到了42.0.0版本?

这是一个负责任的开发问题,也是一个有远见的问题。在有大量依赖关系管理的软件中,不应该轻率的推出不兼容的改变。升级所必须付出的成本是有意义的。发布冲击主版本号的不兼容改变,意味着你深思熟虑过将要发生的震荡,有磕碰主要版本发布不兼容的改变意味着你想通过你的变化的影响,并评估过所涉及的投入产出比。

记录整个公共API是​太辛苦了!

为预计会给其他人使用的软件,提供适当的文档,是一个专业开发者的责任。控制软件的复杂性,是保持项目高效的一个非常重要的组成部分。如果没有谁知道如何使用你的软件,或者用什么方法可以安全地调用,保持项目高效是很难做到的。从长远来看,采用语义化版本控制,坚定的看守一个定义良好的公共API,可以让每一个人都能流畅的做每一件事。

如果不小心,使用副版本号发布了一个不能向后兼容的变更,该怎么办啊?

一旦意识到已经破坏了语义化版本规范,要发布修正了问题,并且恢复向后兼容的新的主版本号。即便是这样,这也是一次不能接受的版本发布。如果方便,一定要记录有问题的版本,并通知你的用户,让他们意识到问题的存在。

如果更新了自己的依赖 但不改变公共API,版本号应该怎么规划?

这是向后兼容的,因为不影响公共API。如果软件与你的包有相同的依赖,有可能会有自己的依赖关系规范,而且软件的作者也会关切任何有可能的冲突。确定这个依赖变更是补丁级别的,还是副版本级别的,取决于你更新你的依赖是要修正一个BUG,还要要引入一组新的功能。我们通常期待是后者,哪怕增加大量的代码。因为在这种情况下,就显然是一个副版本级别的变更了。

如果在不经意间,以不符合版本规范的方式,改了变公共API怎么办(也就是,在一个补丁版本的发布中,源代码错误的引入了一个主版本级别的重大变更)?

那你就发挥出色的判断能力吧。如果拥有大量的忠实拥趸,愿意委曲求全的回到公共API的预期轨道上来,那你最好发布一个主版本。哪怕没什么修改,严格的说也只是补丁级别的。请记住,语义化版本控制是通过版本号的变更来传达意图的。如果变更对你的用户很重要,就使用版本号通知他们。

我应该如何处理以后要废弃的功能?

废弃某些功能,在软件开发中很常见的,通常也会推动软件向前发展。

在废弃公共API的一部分时,你要做两件事:

  1. 更新你的文档,让用户知道这些变更。
  2. 发布包含废弃功能的副版本。

你在主版本中彻底删除这些功能之前,至少要在发布的一个副版本中包含这些功能,好让用户平滑的迁移到新的API上来。

在语义化版本控制中,版本号的长度有限制吗?

没有什么限制,但是你最好保持理智。比如,一个版本号有255个字符,就有点出格了。另外,在开发团队中具体的制度可能会有一些自定义的长度限制。

关于作者

语义化版本控制规范是由Tom Preston-Werner编写的。他是Gravatars 的创始人,也是GitHub的共同创办人。

如果你有一些反馈,可以在GitHub上提交一个问题

许可证

知识共享 - CC 3.0

参考资料

使用JSDoc3生成javascript项目的API文档

JSDoc样式的注释

选用JSDoc3作为注释规范,文档生成工具使用grunt-jsdoc,本文不再介绍选型过程和原因。对JSDoc3的深入学习使用,可以参考入门教程http://usejsdoc.org/index.html

JSDoc注释的样式如下例,与单行注释 // 和多行注释 /**/ 不同,而是类似于JAVA的JDoc和PHP的PHPDoc。

/**
* JSDoc注释。
*/

JSDoc的常用标签

函数注释示例

/**
* 函数注释的示例。
* @param {Integer} augend 被加数。
* @param {Integer} addend 加数。
* @return {Integer} 两数之和。
* @example
* add(1, 2) => 3
*/
function add(augend, addend){
    return augend + addend;
}

参数注释

@param 用于对函数、类的方法的参数进行注释,是JSDoc中最常用的注释标签。

@param 注释必须指定一个参数名,也可以有一个用大括号括起来的参数类型,以及参数的描述信息。参数类型可以是javascript内置的数据类型,如Array、Boolean、Date、Function、Number Object 、String 等,还可以是其他JSDoc所支持的(英文没看太懂,以后用到再认真学习)。

The parameter type can be a built-in JavaScript type, such as string or Object, or a JSDoc namepath to another symbol in your code. If you have written documentation for the symbol at that namepath, JSDoc will automatically link to the documentation for that symbol. You can also use a type expression to indicate, for example, that a parameter is not nullable or can accept any type; see the @type documentation for details.

下面直接使用http://usejsdoc.org/tags-param.html文档中的例子,说明 @param 标签中如何使用参数名、参数类型和参数描述信息。

只有参数名的注释:

/**
 * @param somebody
 */
function sayHello(somebody) {
    alert('Hello ' + somebody);
}

包括参数名和参数类型的注释:

/**
 * @param {string} somebody
 */
function sayHello(somebody) {
    alert('Hello ' + somebody);
}

包括参数名、参数类型和参数描述的注释:

/**
 * @param {string} somebody Somebody's name.
 */
function sayHello(somebody) {
    alert('Hello ' + somebody);
}

返回值注释

@return 说明函数的返回值。例如:

  • @return {Number}
  • @return {Number} Sum of a and b
  • @return {Number|Array} Sum of a and b or an array that contains a, b and the sum of a and b.

参见:http://usejsdoc.org/tags-returns.html

模块注释

@module标签用于标记当前代码文件属于哪个模块。

@link@see 标签中,使用 module:moduleName 可以链接到一个模块。例如,使用 {@link module:foo/bar},可以链接到由 "@module foo/bar 定义的模块。

如果没有提供模块名,将使用模块文件所在路径及文件名作模块名。

参考引用注释

@see 标签可以指向一个相关的引用。示例如下:

/**
 * Both of these will link to the bar function.
 * @see {@link bar}
 * @see bar
 */
function foo() {}

// Use the inline {@link} tag to include a link within a free-form description.
/**
 * @see {@link foo} for further information.
 * @see {@link http://github.com|GitHub}
 */
function bar() {}

类的注释

  • @name :类名称
  • @class :类描述
  • @constructor :表明这是一个构造函数,非常重要。
  • @extends :类继承的父类。
  • @type :数据的类型,主要用来注释属性。
  • @default :默认值,主要用来注释属性。
  • @abstract 标明一个成员是抽象的,需要子类去实现。
  • @public@protected@private:类、方法或属性的访问权限

类的注释示例

要把JSDoc3的注释生成API类库文档,@lends 是个很要紧的标签。

例如,@lends Sample.prototype 表示下面的对象归属于Sample。

较详尽的使用说明参见http://usejsdoc.org/tags-lends.html

有关类的定义和注释示例,如下:

/**
* @name Sample
* @class 示例类
* @public
* @constructor
*/
function Sample(){
    this.something = [];
}

Sample.prototype = 
/** @lends Sample.prototype*/
{
    /**
    * 属性示例。
    * @private
    * @type {Array}
    * @default []
    */
    something : [],

    /**
    * 方法示例。
    * @public
    * @param {String} arg 跟踪方法插件。
    */
    doSomething: function(arg){
    }
};

其他常用注释

  • @example : 示例代码。

  • @enum [<type>] : 一组同样类型的静态属性集合。switch 语句中的分支应该只使用枚举。

  • @overview :对当前代码文件的描述。

  • @copyright :代码的版权信息。

  • @author <name> [<emailAddress>] :代码的作者信息。

  • @version :当前代码的版本。

README.md 是很好的

如果你有为项目写说明文档的好习惯,碰巧又使用的是MarkDown格式,碰巧文件名又是README.md,那就很好了。

把README.md文件放在代码清单里边,JSDoc工具是自动为你生成API文档的首页,什么系统概况、设计需求、设计方案及版本更新记录等等的内容都可以放进来。

Grunt自动构建的配置

Grunt的安装使用,请参考教程《Grunt的安装和使用》

提示:JSDoc某些配置有git依赖, 需要在命令行中可以执行git命令。最好先安装一个msysgit(http://msysgit.github.io/),然后在环境变量中增加git的bin目录。

使用JSDoc3插件,在package.json中的NPM依赖配置参考,如下:

"devDependencies": {
    ... ...
    "grunt-jsdoc": "~0.5.4",
    "ink-docstrap": "~0.3.0",
    ... ...
}

使用JSDoc3插件,在Gruntfile中的配置参考,如下:

jsdoc: {
  dist : {
      src: ['README.md', 'src/sample.js'], 
      options: {
        destination: 'api',
        template: "libs/jsdoc3/docstrap/template",
        configure: "libs/jsdoc3/docstrap/template/jsdoc.conf.json"            
      }
  }
}

详细使用方法和参数,参考:https://github.com/krampstudio/grunt-jsdoc-plugin

参考资料