介绍
代码审查已成为现代软件开发过程不可分割的一部分。 随着分布式版本控制系统的出现,特别是自GitHub诞生以来,pull request-review-merge模型在软件开发社区得到了普及。 然而,GitHub的内置pull请求审查系统有很多需要。 因此,存在许多与GitHub集成的第三方代码审查工具来改进流程。 ReviewNinja是一个这样的工具。
ReviewNinja增加了对香草拉GitHub的要求审核经验之上的一些功能。 它使我们能够通过给“忍者明星”明确签署一份拉要求的能力,所以有像条评论没有更多的需要:shipit:
LGTM
或其他流行的约定。 而且,您可以设置策略来阻止合并若拉请求不是由至少2个团队成员签字,或者如果有人喜欢添加评论!fix
上拉请求。
ReviewNinja是由SAP开发和开源的。 它有一个托管版本 ,但我们可以在我们自己的服务器上部署它,使用它为我们的私人GitHub的仓库。
在本指南中,您将使用部署在DigitalOcean一个ReviewNinja实例Docker和CoreOS 。 一个生产ReviewNinja实例有一个运动部件少,所以我们将使用docker-machine
创建并控制远程主机Docker,以及docker-compose
描述,构建和部署我们的。 我们将使用CoreOS作为Docker主机,这是为云部署定制的最小Linux分发。 全新安装CoreOS只有已systemd
和Docker守护进程,所以我们提供我们的应用程序更多的资源。
先决条件
要完成本教程,您需要:
- Docker,
docker-machine
和docker-compose
安装在本地计算机上,这样你就可以建立,我们将部署应用程序图像。 您可以按照官方的安装文档的Docker获得这些工具进行配置。 这两种docker-machine
和docker-compose
与Docker应用在OSX和Windows自动安装,或者您也可以手动进行使用这些链接安装: - Git安装在本地机器上,因此您可以克隆ReviewNinja存储库以创建容器。 按照官方的Git安装文档 ,如果你需要实现这一先决条件。
- 一个DigitalOcean访问令牌既读取和写入权限,您可以通过访问生成的应用程序和API页面。 复制此令牌,因为你需要使用它与
docker-machine
创建主机。 - 其中1GB CoreOSDroplet,我们将使用配置
docker-machine
在本教程中。 - 一个GitHub的帐户。
第1步 - 创建和激活基于CoreOS的Docker主机
让我们为我们的部署设置基础设施。 该docker-machine
工具,可以提供远程机器的Docker主机和从本地计算机控制它们。 它为许多流行的云提供商,包括DigitalOcean提供驱动程序。 我们将使用docker-machine
创建一个CoreOSDroplet对我们Docker的主机。
切换到您的终端,并使用您的DigitalOcean访问令牌发出以下命令:
docker-machine create --driver=digitalocean \
--digitalocean-access-token=DIGITAL_OCEAN_ACCESS_TOKEN \
--digitalocean-image=coreos-stable \
--digitalocean-region=nyc3 \
--digitalocean-size=1GB \
--digitalocean-ssh-user=core \
reviewninja
我们告诉docker-machine
创建一个名为Dropletreviewninja
在NYC3
使用数据中心coreos-stable
图像与1GB
的内存。 请注意,我们指定--ssh-user=core
,因为在CoreOS安装的默认用户为core
。
运行此命令时,您将看到以下输出:
OutputRunning pre-create checks...
Creating machine...
(reviewninja) Creating SSH key...
(reviewninja) Creating Digital Ocean droplet...
(reviewninja) Waiting for IP address to be assigned to the Droplet...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with coreOS...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env reviewninja
让我们来看看这个新的Droplet被认可docker-machine
。 运行命令:
docker-machine ls
你会看到下面的输出,表明Docker主机reviewminja
是在使用一个远程IP地址运行digitalocean
驱动程序:
OutputNAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
reviewninja digitalocean Running tcp://your_ip_address:2376 v1.10.3
当我们创建Docker主机时,输出的最后一行告诉我们下一步做什么。 它说:
OutputTo see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env reviewninja
所以让我们运行该命令:
docker-machine env reviewninja
您会看到以下消息:
Outputexport DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://your_server_ip:2376"
export DOCKER_CERT_PATH="/home/kevin/.docker/machine/machines/reviewninja"
export DOCKER_MACHINE_NAME="reviewninja"
# Run this command to configure your shell:
# eval $(docker-machine env reviewninja)
那么这里发生了什么? Docker体系结构使用客户端 - 服务器模型。 Docker客户端可以通过Unix套接字或通过TCP进行通信。 通常,我们的Docker客户端通过Unix套接字与本地安装的Docker引擎进行通信。 但是,有一些环境变量可以设置为告诉Docker客户端通过TCP与Docker主机通信。 你看到的输出是一系列shell命令来设置环境变量。
最后一部分说:
Output# Run this command to configure your shell:
# eval $(docker-machine env reviewninja)
当您运行命令,你告诉shell来执行这些命令该设置将用于后续的环境变量docker
命令。
所以,在你的shell中执行该命令:
eval $(docker-machine env reviewninja)
现在,如果你执行docker info
,您将看到有关远程Docker守护进程,而不是当地的Docker守护进程的信息:
docker info
该命令的输出将如下所示:
OutputContainers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 1.10.3
[...]
Labels:
provider=digitalocean
注 :在运行您可能会收到以下错误docker
命令:
Error response from daemon: client is newer than server (client API version: 1.24, server API version: 1.22)
这意味着您使用的Docker客户端版本与服务器的版本不兼容。 为了解决这个问题,环境变量设置DOCKER_API_VERSION
到相同的版本作为服务器。 例如,如果服务器需要版本1.22,请执行以下命令:
export DOCKER_API_VERSION=1.22
然后尝试再次运行Docker命令。
我们的远程Docker主机现在可以通过Docker配置和访问。 在我们可以创建一个ReviewNinja容器之前,我们需要使用GitHub做一些工作。
第2步 - 注册GitHub OAuth应用程序
ReviewNinja需要使用GitHub的API访问您的存储库,所以我们将注册我们的ReviewNinja安装为GitHub OAuth应用程序。
首先,我们需要找出我们的服务器的IP地址。 我们可以使用docker-machine
命令这样做:
docker-machine ip reviewninja
记录此命令显示的IP地址。 然后登录到您的GitHub帐户,并进入设置- >应用程序的OAuth - >开发应用程序 ,并按下注册一个新的应用程序按钮。
一旦您获得新应用程序的表单,请输入以下信息:
- 设置名称
review-ninja
。 - 设为首页网址
http:// your_ip_address
。 - 设置授权回调URL到
http:// your_ip_address /auth/GitHub/callback
。
然后,按注册申请按钮保存更改并创建应用程序。 这将在屏幕上显示新创建的应用程序。
除客户端ID和客户端密钥安全的地方的价值; 您很快就会将它们添加到ReviewNinja应用程序配置中。
现在,你有你的钥匙,让我们开始建立我们的ReviewNinja实例。
第3步 - 创建ReviewNinja Docker容器
ReviewNinja是一个依赖于由MongoDB支持的存储层的Node.js应用程序。 因为我们把它放在生产环境中,我们将Node.js应用程序放在代理服务器后面,所以应用程序服务器不会直接暴露给互联网。 我们将使用Nginx来实现这个目的。 这是一个很多配置,因此,我们将使用Docker,撰写以声明的方式部署多个相关容器。 我们定义我们想要的配置,然后使用docker-compose
工具,指定所有的运行时环境创建容器。
首先,我们需要获取ReviewNinja源代码。 使用Git在本地机器上克隆源代码:
git clone https://github.com/reviewninja/review.ninja.git
然后导航到项目的文件夹:
cd review.ninja
这个库包含Dockerfile
,它告诉Docker如何构建ReviewNinja应用图像。 如果您在自己喜欢的文本编辑器中打开此文件,则会看到以下内容:
FROM node:0.12.2
COPY . /app
RUN npm install -g bower
RUN cd /app; npm install; bower install --allow-root;
WORKDIR /app
VOLUME ["/certs"]
EXPOSE 5000
CMD ["node", "/app/app.js"]
此文件指定此应用程序将使用的Node.js的版本。 然后,它会将所有当前文件夹中的文件到一个app
文件夹,并安装所有的应用程序依赖。 然后,它暴露的端口5000
和启动应用程序。 如需更详细的介绍Dockerfiles,请参阅本教程 。
该Dockerfile描述ReviewNinja应用程序容器,但我们可以形容我们的栈的组件,包括MongoDB的和Nginx的代理,通过使用一个名为docker-compose.yml
,这是一个YAML文件,配置文件的流行的格式。
你克隆的资源库有一个名为docker-compose-example.yml
,但我们会写我们自己从头文件,因为例如,一个不符合我们的需要。
首先,让我们定义我们的的存储。 创建文件docker-compose.yml
并输入以下配置:
version: "2"
services:
db:
image: mongo
volumes:
- /data:/data/db
该db
服务使用的官方MongoDB的图像上Docker Hub,Docker图像的中央存储库。 根据设计,Docker容器在停止和删除时会丢失它们的运行时状态。 这很好的web
服务,因为它是无状态的。 对于我们的db
服务,我们需要将数据保存到磁盘,所以我们不会失去所有的代码审核数据,如果我们停止或重新启动该服务。 这是volumes
进来。在运行时,Docker守护程序可以运行在容器卷映射到主机上的目录的容器。
在我们的配置中,我们指定了以下内容:
volumes:
- /data:/data/db
该主机的映射/data
文件夹/data/db
在容器中,这恰好是MongoDB的配置写入到容器内的文件夹中。 通过创建这个映射,由应用程序所做的更改在被持久化主机上/data
文件夹,而不是在容器中。
接下来我们定义ReviewNinja应用程序容器。 这种添加到docker-compose.yml
文件,现有的配置后:
services:
db:
[...]
web:
build: .
working_dir: /app/
links:
- db
environment:
MONGODB: mongodb://db/reviewninja
GITHUB_CLIENT: YOUR_GITHUB_APP_ID
GITHUB_SECRET: YOUR_GITHUB_APP_SECRET
注意 :确保web
线垂直向上的db
先前定义为YAML文件挑剔缩进服务定义。
我们使用build .
它告诉docker-compose
该图像应该从建立Dockerfile
,我们只是探讨在当前文件夹中。 然后,我们声明的链接db
的形象,所以内部web
容器,名称db
将解析为IP地址db
容器。 这提供了一个基本的服务发现机制; 我们不必知道的IP地址, db
的时间提前及硬编码的容器或通过环境变量传递给它。 然后我们使用这个链接来定义MONGODB
环境变量,使用mongodb://db/reviewninja
作为值。
填写GITHUB_CLIENT
和GITHUB_SECRET
与客户ID和秘密为您创建GitHub的应用程序。 ReviewNinja应用程序将在运行时读取这些环境变量。
最后,让我们来定义负载均衡服务,将转发来自端口的请求80
到我们的Node.js应用程序使用的端口。 这种配置添加到该文件,用衬它垂直web
刚创建的服务宣言:
services:
web:
[...]
nginx:
image: nginx
ports:
- "80:80"
volumes:
- ./reviewninja.conf:/etc/nginx/conf.d/default
command: /bin/bash -c "echo -e 'upstream backend { server web:5000; }\nserver { listen 80; location / { proxy_pass http://backend; }}' > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
links:
- web
我们使用的正式的Nginx图像从Docker集线器和声明的端口映射80:80
,其结合端口80
主机端口80
在容器中。 然后,我们创建了Nginx的配置文件存储在容器外的卷映射,我们宣布一个容器联动的app
容器,所以我们可以通过名称和代理请求给它找到它。
该command
的声明是很长,所以让我们打破它。 它实际上在一行上运行两个命令。 第一个命令是echo -e ... > /etc/nginx/conf.d/default.conf
,这创造了ReviewNinja,它看起来像这样Nginx的配置文件:
upstream backend {
server web:5000;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
这定义了一个backend
的上游和它指向的web:5000
。 价值web
来自docker-compose.yml
在文件links
部分,端口5000
是Node.js的服务器在使用的端口web
容器。 然后,我们宣布,我们的Nginx服务器将在端口上运行80
在容器上应代理的所有请求backend
,我们的应用程序服务器。
该命令,第二部分nginx -g 'daemon off'
,是运行在容器中的Nginx服务器进程的命令。 我们需要指定daemon off
,因为Nginx的在守护进程模式在默认情况下运行时,从正在运行的进程分离本身。 Docker将从容器入口点分离的任何程序视为“退出”,并终止容器,获取所有进程。 作为经验法则,在Docker容器中运行的任何进程都必须在前台运行。
这里就是整个docker-compose.yml
文件,以防万一你想在移动之前要仔细检查你的配置:
version: "2"
services:
db:
image: mongo
volumes:
- /data:/data/db
web:
build: .
working_dir: /app/
links:
- db
environment:
MONGODB: mongodb://db/reviewninja
GITHUB_CLIENT: YOUR_GITHUB_APP_ID
GITHUB_SECRET: YOUR_GITHUB_APP_SECRET
nginx:
image: nginx
ports:
- "80:80"
volumes:
- ./reviewninja.conf:/etc/nginx/conf.d/default
command: /bin/bash -c "echo -e 'upstream backend { server web:5000; }\nserver { listen 80; location / { proxy_pass http://backend; }}' > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
links:
- web
看看在Docker,撰写文档 ,如果你想探索更多关于语法和选项docker-compose.yml
。
这需要我们为这个应用程序的配置。 保存docker-compose.yml
文件; 是时候部署这个应用程序。
第4步 - 构建和部署容器
我们已经配置docker-compose
来部署我们的应用程序ReviewNinja,一个MongoDB实例来保存数据,和Nginx的代理。 在我们部署这些容器中,让我们验证reviewninja
Docker机仍处于活动状态:
docker-machine active
你应该看到:
Outputreviewninja
如果没有看到该输出,请务必运行
eval $(docker-machine env reviewninja)
再次确保您的环境设置正确。 然后重试。
一旦你确定你有一个积极的机器上,使用docker-compose
打造出你的筹码:
docker-compose build
此过程可能需要很长时间,因为它会下载并配置Docker主机上的ReviewNinja应用程序的所有依赖关系。 您将看到以下输出:
Outputdb uses an image, skipping
Building web
Step 1 : FROM node:0.12.2
0.12.2: Pulling from library/node
[...]
Successfully built 106a1992d538
一旦构建过程完成,请验证您是否具有成功的映像:
docker images
你会看到下面的输出,表明图像reviewninja_web
已成功创建:
OutputREPOSITORY TAG IMAGE ID CREATED SIZE
reviewninja_web latest 106a1992d538 3 minutes ago 946.6 MB
现在我们可以使用一个命令在我们的远程服务器上启动我们的数据库,我们的ReviewNinja应用程序和我们的Nginx代理:
docker-compose up -d
这带来了我们在定义的所有容器docker-compose
文件。 我们使用-d
(用于“分离”),以便在后台运行所有的容器,我们有我们的终端回到我们的控制。
OutputCreating network "reviewninja_default" with the default driver
Pulling db (mongo:latest)...
latest: Pulling from library/mongo
[...]
Digest: sha256:d3f19457c816bb91c5639e3b1b50f67370e3b3a58b812d73446d7b966469c65e
Status: Downloaded newer image for mongo:latest
Creating reviewninja_db_1
Creating reviewninja_web_1
Creating reviewninja_nginx_1
让我们验证容器是否已启动并正在运行。 执行以下命令:
docker ps
您将看到如下所示的输出:
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
29f8e6f770d3 nginx "nginx -g 'daemon off" 43 seconds ago Up 41 seconds 0.0.0.0:80->80/tcp, 443/tcp reviewninja_nginx_1
164564dd450a reviewninja_web "node /app/app.js" 45 seconds ago Up 43 seconds 5000/tcp reviewninja_web_1
7cd9d03eb3b9 mongo "/entrypoint.sh mongo" 46 seconds ago Up 44 seconds 27017/tcp reviewninja_db_1
我们还希望确保服务正常运行。 要做到这一点,我们使用docker logs
命令来查看容器的输出。 让我们查看ReviewNinja Web应用程序的日志。 我们可以通过它的ID,在上市参考值容器CONTAINER ID
在前面的输出列,或它的名字。 在我们的例子中,名字是reviewninja_web_1
,所以让我们看看该容器中的日志:
docker logs reviewninja_web_1
您将看到ReviewNinja应用程序的输出,指示它正在侦听连接:
OutputIn server/app.js
checking configs
✓ configs seem ok
Host: http://localhost:5000
GitHub: https://GitHub.com
GitHub-Api: https://api.GitHub.com
bootstrap certificates
bootstrap static files
apply migrations
[...]
bootstrap mongoose
[...]
bootstrap passport
[...]
bootstrap controller
[...]
bootstrap api
[...]
bootstrap webhooks
[...]
bootstrap monkey patch
✓ bootstrapped, app listening on localhost:5000
输出表明ReviewNinja上监听端口5000
。
要从网络访问它,我们需要使用我们的Docker主机的IP,这是我们的CoreOS服务器。 如果你忘了你的服务器的IP地址,使用docker-machine
找出来。
docker-machine ip reviewninja
在浏览器中http:// your_server_ip
,你会被忍者打hello:
最后,我们准备好使用我们自己的代码来使用应用程序。
第5步 - 使用ReviewNinja与存储库
让我们在测试存储库上试试我们的新的ReviewNinja实例。 我们会提供有关拉取请求的反馈,解决问题,接受更改并合并拉取请求。
首先,我们需要允许ReviewNinja应用程序访问我们的GitHub帐户。 点击登录 ,你会被重定向到GitHub上登录你会被询问是否要允许ReviewNinja访问您的GitHub帐户:
一旦您授权应用程序,您将被带到ReviewNinja的主界面。 如果您有私人仓库,你想ReviewNinja使用,则可以单击启用私人回购协议链接:
然后,您将被重定向到GitHub以修改您的ReviewNinja应用程序的授权,以包括对您的私有仓库的访问:
一旦您授予ReviewNinja您想要的访问权限,您可以添加一个存储库,以便您可以使用ReviewNinja为您的请求工作流。 当它使用ReviewNinja你的第一次,你有机会增加一个样本ReviewNinja-Welcome
库:
创建该示例存储库,以便我们可以浏览一些基本的ReviewNinja功能。 这将在您的帐户下的Github上创建存储库,并将其添加到ReviewNinja。
样品库包含ReadMe.md
是应该概述一些ReviewNinja的代码审查流程的特征文件。 该ReviewNinja-Welcome
库已经有一个拉请求来自分支开放your_github_username -patch-1
具有的更新的副本ReadMe.md
文件。 分支的名称将根据您的用户名而有所不同。
点击该分支,您将看到主代码审查界面,您可以在其中浏览差异并添加评论。 您还将看到拉取请求状态框,其中概述拉取请求的状态和未决问题。
合并拉请求按钮为琥珀色,因为现在拉请求的状态为“待定”。 状态将根据您可以通过单击齿轮按钮调整的条件而改变。 默认情况下,它需要至少1个忍者星为按钮变绿。
我们将在以后的行动中看到,但现在,让我们添加一个行注释。 点击说的那行代码
+ convenience we also have a dropdown menu to add these comments
让我们有点迂腐这里并建议这个词dropdown
应改为drop-down
。 添加使用屏幕右边的评论框注释,将此作为阻塞问题通过添加!fix
你的评论,如如下图:
标记的注释将被视为拉取请求的“问题”,拉取请求的作者需要在ReviewNinja允许它合并之前解决。
刷新页面,现在您会看到合并拉请求按钮上面列出的新问题:
让我们解决这个问题。 在本地机器上,使用Git克隆存储库:
git clone git@GitHub.com:your_github_username/ReviewNinja-Welcome.git
cd ReviewNinja-Welcome
然后检查需要工作的分支:
git checkout your_github_username-patch-1
打开ReadMe.md
在你最喜欢的文本编辑器和更改行说drop-down
,而不是dropdown
:
label ReadMe.md
To add a flag simply leave a comment with your desired flag. For
convenience we also have a drop-down menu to add these comments
automatically.
将文件保存在编辑器中,然后添加并提交更改:
git add ReadMe.md
git commit -m "Address code review feedback"
接下来,将更改推送到Github的分支:
git push origin your_github_username-patch-1
现在,在浏览器中刷新ReviewNinja界面。 你会看到代码的更新,如果你再次点击就行,你可以回复现有注释!fixed
或!resolved
所示,如下图所示:
最后,现在我们对pull请求感到满意了,让我们给它一个忍者明星作为正式签名。 单击Add忍者星按钮:
然后刷新浏览器,并观察拉请求状态更新为“成功”,并合并拉请求按钮为绿色:
您可以通过点击齿轮按钮来自定义提出请求的成功条件:
继续并点击“合并拉请求”。 页面重新加载后(您可能必须手动刷新),您将看到拉取请求的状态更改为“合并”。
有一点要记住:ReviewNinja拉请求 GitHub上拉的请求,反之亦然。 对ReviewNinja的评论将自动反映在GitHub拉取请求页面上,反之亦然。 通过ReviewNinja合并的拉取请求也会反映在GitHub上:
这种双向同步对于想要逐渐迁移到ReviewNinja进行代码审查的团队来说非常有用。
结论
在本教程中,您使用Docker, docker-machine
,以及docker-compose
部署ReviewNinja,多层Web应用程序。 您学习了如何从现有应用程序创建Docker映像,以及如何从舒适的本地终端定义和部署整个基础架构。
您还了解了ReviewNinja的一些强大功能,以及如何使用这些功能来向GitHub拉取请求过程添加一些工作流控制。
快乐代码审查!