项目背景
在一家公司做 DevOps 相关工作,很多年前试用了一些 Git 产品,但不满足我们的流程需要。于是在业余时间开发了这个产品并在内部使用,饱受好评。之后开源,一直维护至今。可用于自建 Git 服务,自带看板和 CI/CD。
项目地址:https://github.com/theonedev/onedev
相比 GitHub/GitLab 有什么特点?
开箱即用的符号搜索和跳转
虽然 IDE 也可以做这些事情,但是我们经常需要切换到以前的 commit 搜索(比如某个 issue 对应的 commit ),这在 IDE 里需要切换工作环境有点麻烦,也有点慢,不如直接打开 onedev 搜索方便。
这个功能使用 ANTLR 分析主流语言的语法,并提取符号定义进行增量存储,速度快,占用空间小。目前支持 Java, JavaScript, C, C++, CSharp, Go, PHP, Python, CSS, SCSS, LESS and R 。GitHub 前两年加入了这个功能,但是好像只是针对主分支; GitLab 需要在 CI 里做 LSIF相关配置,比较麻烦,并会占用大量空间。
在代码评审时也经常跳转去看某个符号的定义。
对仓库代码的正则表达式搜索
可以切换到任意 commit,并进行正则表达式搜索。仓库代码使用 Lucene 分词,并按需增量存储,正则表达式本身先进行分词进行粗略查询,然后在结果里再进行精确匹配来提高速度。
静态分析结果直接标注在源码上,作为代码评审的辅助信息
当然 GitHub 有很多第三方工具可以做这个事情,但发现的问题都是显示在各自的网站上,与代码评审流程割裂开来了,使得一些流程很不方便,比如我们有时需要在源码上对静态分析发现的问题加评审说明等等。另外这些第三方工具一般都需要额外收费。
Issue 字段和状态可定制,以及和 CI/CD 的深度集成
这里 GitHub/GitLab 的简单的 open/close 的状态完全不能满足我们的需求,特别是牵涉到客户创建的 issue 时。如果开发人员在 commit 代码时 close 相关 issue ,客户得到通知会以为这个问题已经解决,于是会问我们应该更新到哪个发行版;而如果在产品发布时 close 相关 issue ,测试人员在拿到测试版时也很困扰,因为相关 issue 还是 open 状态,不知道该测试哪些 issue 。为解决这个问题,我们定制了四个 issue 状态:open ,committed ,test ready 和 released 。当开发人员 commit 代码时,相关 issue 自动迁移到 committed 状态;当包含这些 commit 的代码被构建并部署到测试环境中时,相关 issue 自动迁移到 test ready 状态,并通知 QA ,QA 可以在 issue 的详情页面里了解部署到了哪个测试环境;当测试通过创建发行版时,相关 issue 自动迁移到 released 状态,并通知客户,客户在 issue 的详情页里可以得知关联的发行版。
强大易用的Commit/Issue/Build/Pull Request查询语言
这个也是基于 ANTLR 做的,对语法规则进行预测来实现自动提示。这样无需学习语法就可以直接进行复杂查询,比如我们客户经常做的事情就是在升级前查询当前版本和最新版本之间都有哪些改动等等。查询可以保存并订阅,这样符合相关条件的事件发生时可以及时得到通知。
全功能的 CI/CD ,无需了解 Yaml 语法,上手非常简单
CI/CD 是花精力最多的部分了,虽然 CI/CD 的定义也是以 Yaml 文件的方式存储在仓库中,但提供了 UI 来生成该文件,用户无需了解任何相关语法即可进行配置。
在 Commit 页面可以直接运行 CI/CD 任务,使得 GitOps 来的更直观。灵活可定制的 CI/CD 选项页面让非开发人员也可以很容易的进行部署。
部署一个用于构建的集群及其方便,只需一个 helm 命令就可以部署到 Kubernetes 中,每个构建任务会作为 Pod 运行,同时支持 Windows 和 Linux ;在没有 Kubernetes 的环境中,一行 docker 命令即可启动一个构建的 Agent ,而且 Agent 免于维护,自动升级。
摒弃 Organization ,将项目以树形结构组织以方便设置的继承
自从 GitHub 使用 Organization 后,似乎所有类似的软件都采用这种方式来组织项目了。这种方式对于面向公共服务的云平台而言可能比较合适,但对于公司内部使用感觉没有太大必要。我们的做法是将项目以树形结构组织,下级项目可以自动继承上级项目的设置,也可以按需覆盖。这使得大量项目的配置维护非常容易。
随时对代码进行标注和讨论,而不用依赖于 Pull Request
在浏览源码或者 Diff 时,可以对任意代码块即时发起讨论。讨论的内容将作为代码文档的一部分(即使事后代码改动甚至更名),方便其他人以后对代码进行阅读和理解。不同于其他的Git工具,代码Comment在侧边显示,避免割裂代码上下文,影响阅读。
另外每处讨论形成单独的主题,使相关的人很容易知道哪里有新的改动或回复。
资源占用相比GitHub/GitLab小很多,速度快
个人使用的话,默认情况下一台1核2G的机器足够了,调整下 conf/wrapper.conf 里的内存设置,也可以跑在1核1G的机器上。比 Gitea/Gogs 的资源占用还是多的,不过如果 Gitea/Gogs 要做类似功能,受限于 Golang 的生态,可能要启动一些其他语言写的微服务(比如各种Language Server,Elastic Search 等),最终资源消耗一定不会小。
还有一个优点就是主服务可以运行在 Linux,Mac,Windows,FreeBSD 等多平台上,可以使用内置文件数据库,也可以充分利用公司现有资源连接到 MySql/MariaDB/PostgreSQL/Oracle/SQL Server 等外置数据库。
其他特点诸如自动根据Commit历史推荐合适的代码评审人、markdown 编辑时同步滚动预览(不是简单的算滚动条百分比,而是根据上下文同步)、可定制的 issue 关联、细致的权限设置等就不一一赘叙了。
技术栈
不够时髦,从头到脚 Java 一把撸。不分前后端,所有代码在一个 Maven 项目中( 40 万行代码左右)。使用 Wicket (估计很少人听说)把界面交互和后端逻辑封装在一个组件中,配置界面通过 Annotation 自动生成。依赖注射和插件体系基于 Guice 。在 Eclipse 中启动项目大概耗时 20 秒,不过大部分时间热部署,改动代码后直接刷新页面就可以看到改动。
谢谢关注,感兴趣的朋友点此五分钟教程(创建 react demo,并配置CI):
https://zhuanlan.zhihu.com/p/103410072