微服务架构下RPC IDL及代码如何统一管理?

Han-Ya-Jun · · 3031 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

<section id="nice" data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px; color: black; padding: 0 10px; line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; word-break: break-word; word-wrap: break-word; text-align: left; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; border-bottom: 2px solid rgb(239, 112, 96); font-size: 1.3em;"><span class="prefix" style="display: none;"></span><span class="content" style="display: inline-block; font-weight: bold; background: rgb(239, 112, 96); color: #ffffff; padding: 3px 10px 1px; border-top-right-radius: 3px; border-top-left-radius: 3px; margin-right: 3px;">背景</span><span class="suffix"></span><span style="display: inline-block; vertical-align: bottom; border-bottom: 36px solid #efebe9; border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">随着云原生技术的日益发展和普及,微服务架构下多语言(python,go,php....)多系统之间通过rpc来通信,一旦接口需要升级,协调 server 端有发布和升级,IDL 文件仓库的变更,client 端变更发布就变成了一个很麻烦的事情。我们需要一个方便透明的规范来协调各端,一个更加自动化的工具来协同。以主流的grpc为例来探讨下, 这个 proto 及代码到底放在哪里?应该如何做到自动化版本控制?</p> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"><img src="https://cdn.hanyajun.com/20201125222844.png" alt style="display: block; margin: 0 auto; max-width: 100%;"></figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; border-bottom: 2px solid rgb(239, 112, 96); font-size: 1.3em;"><span class="prefix" style="display: none;"></span><span class="content" style="display: inline-block; font-weight: bold; background: rgb(239, 112, 96); color: #ffffff; padding: 3px 10px 1px; border-top-right-radius: 3px; border-top-left-radius: 3px; margin-right: 3px;">方案一:放在各自的代码仓库</span><span class="suffix"></span><span style="display: inline-block; vertical-align: bottom; border-bottom: 36px solid #efebe9; border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">如下图所示,直接将项目所依赖到的以及自己的所有 proto 文件和client代码都存放在 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">protobuf/</code> 目录下,不借助外部工具。</p> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;"><img src="https://cdn.hanyajun.com/20201125222907.png" alt style="display: block; margin: 0 auto; max-width: 100%;"> 很明显该方案有以下优缺点。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span class="prefix" style="display: none;"></span><span class="content">缺点:</span><span class="suffix" style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">1️⃣ 项目所有依赖的 proto 都存储在各自项目的代码仓库下,因此所有依赖 proto 都需要人工的向其它业务组 “要” 来,再放到 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">protobuf/</code> 目录下,人工介入极度麻烦。依赖多了拷贝会成为一种负担。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">2️⃣ 版本的控制和更新没有办法去维护,沟通成本太高。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">3️⃣ 代码的复用性比较差。</p> </section></li></ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span class="prefix" style="display: none;"></span><span class="content">优点:</span><span class="suffix" style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;">简单易用,每个项目的proto依赖一目了然。不需要看这看那。</section></li></ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; border-bottom: 2px solid rgb(239, 112, 96); font-size: 1.3em;"><span class="prefix" style="display: none;"></span><span class="content" style="display: inline-block; font-weight: bold; background: rgb(239, 112, 96); color: #ffffff; padding: 3px 10px 1px; border-top-right-radius: 3px; border-top-left-radius: 3px; margin-right: 3px;">方案二:独立proto仓库</span><span class="suffix"></span><span style="display: inline-block; vertical-align: bottom; border-bottom: 36px solid #efebe9; border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">每个项目都有自己的proto仓库。需要依赖的都从proto仓库拉(包括服务自己)。</p> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;"><img src="https://cdn.hanyajun.com/20201125223327.png" alt style="display: block; margin: 0 auto; max-width: 100%;"> 不过这种方式也是有比较明显的缺点:</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span class="prefix" style="display: none;"></span><span class="content">缺点:</span><span class="suffix" style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">1️⃣ 各服务需要同时关注自己的服务本身还有服务的proto仓库,开发时需要先在proto仓库定义好proto和生成好client代码,所以在开发时需要在服务仓库和proto仓库切换。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">2️⃣ 如果服务依赖的太多,也有可能跨业务组,例如下图,如果跨组之后,可能需求找业务组负责人开多个proto仓库权限。还需要一个一个地去依赖。</p> </section></li></ul> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"><img src="https://cdn.hanyajun.com/20201125223356.png" alt style="display: block; margin: 0 auto; max-width: 100%;"></figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;">3️⃣ 每次有新的服务都需要对应去申请一个proto仓库比较麻烦。</section></li></ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span class="prefix" style="display: none;"></span><span class="content">优点:</span><span class="suffix" style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">1️⃣ 各自服务有各自的proto仓库,方便版本维护和升级。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">2️⃣ 依赖时可以按需拉取。</p> </section></li></ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; border-bottom: 2px solid rgb(239, 112, 96); font-size: 1.3em;"><span class="prefix" style="display: none;"></span><span class="content" style="display: inline-block; font-weight: bold; background: rgb(239, 112, 96); color: #ffffff; padding: 3px 10px 1px; border-top-right-radius: 3px; border-top-left-radius: 3px; margin-right: 3px;">方案三:集中仓库</span><span class="suffix"></span><span style="display: inline-block; vertical-align: bottom; border-bottom: 36px solid #efebe9; border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">按业务组维度来管理proto仓库,这样的话如果依赖某个业务组多个依赖时只需要拉取一个proto仓库即可。同时每次新起一个服务时,只需要在各自业务组的prooto仓库加上自己服务的,不需要单独去申请一个自己服务的proto仓库。</p> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"><img src="https://cdn.hanyajun.com/20201125223755.png" alt style="display: block; margin: 0 auto; max-width: 100%;"></figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span class="prefix" style="display: none;"></span><span class="content">优点:</span><span class="suffix" style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">1️⃣ 依赖多个服务的proto时只需要依赖中央仓库即可。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">2️⃣ 新增服务时不需要单独去申请proto仓库,只需要在各自业务组的proto仓库添加即可。</p> </section></li></ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span class="prefix" style="display: none;"></span><span class="content">缺点:</span><span class="suffix" style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">1️⃣ 各服务开发时还是需要关注两个仓库,需要切来切去。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">2️⃣ 每个中央仓库下不能独立的对各服务的proto进行版本管理。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">3️⃣ 可能只依赖某个svc的proto,而多引入了一些其他不必要的。</p> </section></li></ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; border-bottom: 2px solid rgb(239, 112, 96); font-size: 1.3em;"><span class="prefix" style="display: none;"></span><span class="content" style="display: inline-block; font-weight: bold; background: rgb(239, 112, 96); color: #ffffff; padding: 3px 10px 1px; border-top-right-radius: 3px; border-top-left-radius: 3px; margin-right: 3px;">方案四:镜像仓库+git branch</span><span class="suffix"></span><span style="display: inline-block; vertical-align: bottom; border-bottom: 36px solid #efebe9; border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">为解决上述方案的一些痛点,综合各方案的优点我们在中央仓库的基础之上采取了镜像仓库结合git branch的方式。 <img src="https://cdn.hanyajun.com/20201125223821.png" alt style="display: block; margin: 0 auto; max-width: 100%;"> 说明:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;">1️⃣ 各业务组的中央仓库的master的readme维护了各分支和各服务的对应关系,如下图。</section></li></ul> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"><img src="https://cdn.hanyajun.com/20201125223902.png" alt style="display: block; margin: 0 auto; max-width: 100%;"></figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">2️⃣ 这样主要是为了新增新的svc时可以拿到下一个分支的分支名(由于go.mod的分支版本管理限制,只能以V2,V3这种命名),同时方便人们去辨识自己依赖的svc在哪个模块。common表示是所有svc proto的集合分支。每次新增一个服务时便会在cicd的过程中往这个reame添加说明。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">3️⃣ 中央仓库的分支的readme维护了各自自己的版本情况。</p> </section></li></ul> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"><img src="https://cdn.hanyajun.com/20201125224048.png" alt style="display: block; margin: 0 auto; max-width: 100%;"></figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">4️⃣ 使用时可以根据自己的需要去依赖对应的分支的版本即可。</p> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">5️⃣ python cleint版本和go的版本都是一一对应的。</p> </section></li></ul> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"><img src="https://cdn.hanyajun.com/20201125224114.png" alt style="display: block; margin: 0 auto; max-width: 100%;"></figure> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">6️⃣ 各svc只需要依赖一个.gitlab.yml文件即可实现。具体的gitlab cicd的job如下:</p> <pre class="custom" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/point.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; display: -webkit-box; -webkit-overflow-scrolling: touch; font-size: 14px; word-wrap: break-word; padding: 2px 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96); padding-top: 15px; background: #282c34; border-radius: 5px;"><br><span class="hljs-string" style="color: #98c379; line-height: 26px;">.push_tmpl:</span>&nbsp;<span class="hljs-meta" style="color: #61aeee; line-height: 26px;">&amp;push_proto</span><br>&nbsp;&nbsp;<span class="hljs-attr" style="color: #d19a66; line-height: 26px;">script:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-bullet" style="color: #61aeee; line-height: 26px;">-</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">"push&nbsp;test"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-bullet" style="color: #61aeee; line-height: 26px;">-</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$CI_PROJECT_NAME</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-bullet" style="color: #61aeee; line-height: 26px;">-</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">|<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userMail=$GITLAB_USER_EMAIL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;config&nbsp;--global&nbsp;user.email&nbsp;"$GITLAB_USER_EMAIL"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userName=${userMail%@*}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"$userMail"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;config&nbsp;--global&nbsp;user.name&nbsp;"$userName"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;clone&nbsp;-v&nbsp;https://xxxxx/proto-center.git<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cd&nbsp;proto-center<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;[&nbsp;`grep&nbsp;-c&nbsp;$CI_PROJECT_NAME&nbsp;README.md`&nbsp;-eq&nbsp;'0'&nbsp;];then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"-&nbsp;$CI_PROJECT_NAME--&gt;v$(sed&nbsp;-n&nbsp;'$p'&nbsp;README.md&nbsp;|&nbsp;awk&nbsp;-F&nbsp;"--&gt;v"&nbsp;'{print&nbsp;$2+1}'&nbsp;|&nbsp;head)"&nbsp;&gt;&gt;README.md<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;export&nbsp;branchName=$(sed&nbsp;-n&nbsp;'$p'&nbsp;README.md&nbsp;|&nbsp;awk&nbsp;-F&nbsp;"--&gt;"&nbsp;'{print&nbsp;$2}')<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$branchName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;add&nbsp;.&nbsp;&amp;&amp;&nbsp;git&nbsp;commit&nbsp;-m&nbsp;"add&nbsp;$CI_PROJECT_NAME&nbsp;"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;&nbsp;https://xxxxxxxx/proto-center.git&nbsp;master<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;checkout&nbsp;-b&nbsp;$branchName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mkdir&nbsp;-p&nbsp;$CI_PROJECT_NAME&nbsp;&amp;&amp;&nbsp;cp&nbsp;-r&nbsp;../protobuf/*&nbsp;$CI_PROJECT_NAME/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;go&nbsp;mod&nbsp;init&nbsp;xxxxxxxx/proto-center/$branchName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;go&nbsp;mod&nbsp;tidy<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;add&nbsp;.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;commit&nbsp;-m&nbsp;"add&nbsp;&nbsp;$CI_PROJECT_NAME&nbsp;proto"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;--set-upstream&nbsp;https:/xxxxxxxx/proto-center.git&nbsp;$branchName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;checkout&nbsp;v2<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mkdir&nbsp;-p&nbsp;$CI_PROJECT_NAME&nbsp;&amp;&amp;&nbsp;cp&nbsp;-r&nbsp;../protobuf/*&nbsp;$CI_PROJECT_NAME/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;add&nbsp;.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;commit&nbsp;-m&nbsp;"add&nbsp;&nbsp;$CI_PROJECT_NAME&nbsp;proto"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;&nbsp;https://xxxxxxxx/proto-center.git&nbsp;v2<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;export&nbsp;branchName=$(grep&nbsp;$CI_PROJECT_NAME&nbsp;README.md&nbsp;&nbsp;|&nbsp;awk&nbsp;-F&nbsp;"--&gt;"&nbsp;'{print&nbsp;$2}'&nbsp;|&nbsp;head)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;checkout&nbsp;$branchName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rm&nbsp;-rf&nbsp;$CI_PROJECT_NAME/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mkdir&nbsp;-p&nbsp;$CI_PROJECT_NAME<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cp&nbsp;-r&nbsp;../protobuf/*&nbsp;$CI_PROJECT_NAME/&nbsp;&amp;&amp;&nbsp;git&nbsp;add&nbsp;.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;commit&nbsp;-m&nbsp;"update&nbsp;&nbsp;$CI_PROJECT_NAME&nbsp;proto"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;https://xxxxxxxx/proto-center.git&nbsp;$branchName;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;checkout&nbsp;v2<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rm&nbsp;-rf&nbsp;$CI_PROJECT_NAME/<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mkdir&nbsp;-p&nbsp;$CI_PROJECT_NAME<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cp&nbsp;-r&nbsp;../protobuf/*&nbsp;$CI_PROJECT_NAME/&nbsp;&amp;&amp;&nbsp;git&nbsp;add&nbsp;.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;commit&nbsp;-m&nbsp;"update&nbsp;&nbsp;$CI_PROJECT_NAME&nbsp;proto"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;https://xxxxxxxx/proto-center.git&nbsp;v2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fi<br></span></code></pre> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">7️⃣ 中央仓库的gitlab的cicd的job如下:</p> <pre class="custom" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/point.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; display: -webkit-box; -webkit-overflow-scrolling: touch; font-size: 14px; word-wrap: break-word; padding: 2px 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96); padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-string" style="color: #98c379; line-height: 26px;">.buld_tmpl:</span>&nbsp;<span class="hljs-meta" style="color: #61aeee; line-height: 26px;">&amp;tag_proto</span><br><br>&nbsp;&nbsp;<span class="hljs-attr" style="color: #d19a66; line-height: 26px;">script:</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-bullet" style="color: #61aeee; line-height: 26px;">-</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">"tag&nbsp;proto&nbsp;"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-bullet" style="color: #61aeee; line-height: 26px;">-</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">|<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userMail=$GITLAB_USER_EMAIL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userName=${userMail%@*}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"$userMail"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;config&nbsp;--global&nbsp;user.email&nbsp;$userMail<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;config&nbsp;--global&nbsp;user.name&nbsp;$userName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;branch=$CI_BUILD_REF_NAME<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isnottag="false"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;describe&nbsp;--tag&nbsp;||&nbsp;isnottag="true"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;clone&nbsp;-b&nbsp;$branch&nbsp;-v&nbsp;https://xxxxx/proto-center.git<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cd&nbsp;proto-center<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userMail=$(&nbsp;git&nbsp;log&nbsp;--pretty=format:%ae&nbsp;${CI_COMMIT_SHA}&nbsp;-1)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;userName=${userMail%@*}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"$userMail"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;config&nbsp;--global&nbsp;user.email&nbsp;$userMail<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;config&nbsp;--global&nbsp;user.name&nbsp;$userName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;version=""<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;[&nbsp;$isnottag&nbsp;=&nbsp;"true"&nbsp;];then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$isnottag<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;version=$branch.0.1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$version<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;tag&nbsp;$version<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;&nbsp;https://xxxxx/proto-center.git&nbsp;--tags<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"-&nbsp;$version"&nbsp;&gt;&gt;&nbsp;README.md<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;add&nbsp;.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;commit&nbsp;-m&nbsp;"add&nbsp;$version"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;&nbsp;https://xxxxx/proto-center.git&nbsp;$branch<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$isnottag<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;version_ref=$(git&nbsp;describe&nbsp;--tags&nbsp;|&nbsp;awk&nbsp;-F&nbsp;"-"&nbsp;'{print&nbsp;$1}'&nbsp;|&nbsp;head)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$version_ref<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;version=`echo&nbsp;$version_ref&nbsp;|&nbsp;awk&nbsp;-F.&nbsp;-v&nbsp;OFS=.&nbsp;'NF==1{print&nbsp;++$NF};&nbsp;NF&gt;1{if(length($NF+1)&gt;length($NF))$(NF-1)++;&nbsp;$NF=sprintf("%0*d",&nbsp;length($NF),&nbsp;($NF+1)%(10^length($NF)));&nbsp;print}'`<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$version<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;tag&nbsp;$version<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;&nbsp;https://xxxxx/proto-center.git&nbsp;&nbsp;--tags<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"-&nbsp;$version"&nbsp;&gt;&gt;&nbsp;README.md<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;add&nbsp;.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;commit&nbsp;-m&nbsp;"add&nbsp;$version"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;git&nbsp;push&nbsp;&nbsp;https://xxxxx/proto-center.git&nbsp;$branch<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fi<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mkdir&nbsp;-p&nbsp;python<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cp&nbsp;-r&nbsp;**/*.proto&nbsp;python<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pkgName=$(&nbsp;grep&nbsp;"\\--&gt;"&nbsp;README.md&nbsp;|&nbsp;tail&nbsp;-1&nbsp;|&nbsp;awk&nbsp;-F&nbsp;"--&gt;v"&nbsp;'{print&nbsp;$1}'&nbsp;|&nbsp;awk&nbsp;-F&nbsp;"&nbsp;"&nbsp;'{print&nbsp;$2}')<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pkgName=${pkgName//-/_}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$pkgName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;export&nbsp;pip_pkg_name=$pkgName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;$version<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;export&nbsp;pip_tag_name=$version<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pip&nbsp;install&nbsp;grpcio-tools==1.4.0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pip&nbsp;install&nbsp;protobuf==3.3.0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"#!/bin/env&nbsp;python<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;-*-&nbsp;encoding=utf8&nbsp;-*-<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;import&nbsp;os<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from&nbsp;setuptools&nbsp;import&nbsp;(setup,&nbsp;find_packages)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;version&nbsp;=&nbsp;os.getenv('pip_tag_name')<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;os.getenv('pip_pkg_name')<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setup(<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name=name,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;version=version,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;description='LLS&nbsp;grpc&nbsp;protocol',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;packages=find_packages(exclude=[]),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;include_package_data=True,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;author='LLS&nbsp;DEV&nbsp;Team',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;author_email='',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;package_data={'':&nbsp;['*.*']},<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;install_requires=[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'grpcio==1.18.0',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'protobuf==3.3.0'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zip_safe=False,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classifiers=[<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'Programming&nbsp;Language&nbsp;::&nbsp;python&nbsp;::&nbsp;2.7',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)"&nbsp;&gt;&nbsp;python/setup.py<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[distutils]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index-servers&nbsp;=&nbsp;internal<br></span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">[internal]</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-attr" style="color: #d19a66; line-height: 26px;">repository:</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">https://xxxxx.com/</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-attr" style="color: #d19a66; line-height: 26px;">username:</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">xxxxx</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-attr" style="color: #d19a66; line-height: 26px;">password:</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">xxxxx</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">"&nbsp;&gt;&nbsp;~/.pypirc<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mkdir&nbsp;-p&nbsp;python/$pkgName<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"</span><span class="hljs-string" style="color: #98c379; line-height: 26px;">"&nbsp;&gt;&gt;&nbsp;python/$pkgName/__init__.py<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;python&nbsp;-m&nbsp;grpc_tools.protoc&nbsp;-I&nbsp;python/&nbsp;--python_out=python/$pkgName&nbsp;--grpc_python_out=python/$pkgName/&nbsp;python/*.proto<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cd&nbsp;python<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ls<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;python&nbsp;setup.py&nbsp;bdist_wheel&nbsp;upload&nbsp;-r&nbsp;internal<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cd&nbsp;..<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mkdir&nbsp;-p&nbsp;python3<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cp&nbsp;-r&nbsp;-n&nbsp;**/*.proto&nbsp;python3<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;"</span><span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">#!/bin/env&nbsp;python</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">#&nbsp;-*-&nbsp;encoding=utf8&nbsp;-*-</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">import</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">os</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">from</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">setuptools</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">import</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">(setup,</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">find_packages)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">version</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">=</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">os.getenv('pip_tag_name')</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">name</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">=</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">os.getenv('pip_pkg_name')</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">setup(</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">name=name,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">version=version,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">description='LLS</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">grpc</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">protocol',</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">packages=find_packages(exclude=[]),</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">include_package_data=True,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">author='LLS</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">DEV</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">Team',</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">author_email='',</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">package_data={'':</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">['*.*']},</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">install_requires=[</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'grpcio==1.18.0'</span><span class="hljs-string" style="color: #98c379; line-height: 26px;">,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'protobuf==3.12.4'</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">],</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">zip_safe=False,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">classifiers=[</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'Programming&nbsp;Language&nbsp;::&nbsp;python&nbsp;::&nbsp;3.7'</span><span class="hljs-string" style="color: #98c379; line-height: 26px;">,</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">],</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">)"</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">&gt;</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3/setup.py</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-m</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">pip</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">install</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">grpcio-tools==1.4.0</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-m</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">pip</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">install</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">protobuf</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">mkdir</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-p</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3/$pkgName</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">""</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">&gt;&gt;</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3/$pkgName/__init__.py</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-m</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">grpc_tools.protoc</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-I</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3/</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">--python_out=python3/$pkgName</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">--grpc_python_out=python3/$pkgName/</span>&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3/*.proto</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">cd</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3/$pkgName</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">ls</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">pb_files=`ls</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">|</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">grep</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-v</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'__init__'</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">|</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">grep</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-v</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'grpc.py'</span><span class="hljs-string" style="color: #98c379; line-height: 26px;">`</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$pb_files</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">need_replace_strs=()</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">for</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">pb_file</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">in</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">${pb_files[@]}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">do</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">prefix=${pb_file/.py/}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">after_handle_package_name=${prefix//_/__}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">need_replace_str="import</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$prefix</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">as</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$after_handle_package_name"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$need_replace_str</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">need_replace_strs[${#need_replace_strs[@]}]="$need_replace_str"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">#echo&nbsp;${need_replace_strs[0]}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">done</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">need_replace_str_num=${#need_replace_strs[@]}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">all_files=`ls</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">|</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">grep</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-v</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'__init__'</span><span class="hljs-string" style="color: #98c379; line-height: 26px;">`</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$all_files</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">for</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">file</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">in</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">${all_files[@]}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">do</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">for</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">((i=0;i&lt;$need_replace_str_num;i++))</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">do</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">need_replace_str=${need_replace_strs[${i}]}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$need_replace_str</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">sed</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-i</span>&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">"s/^$need_replace_str$/from&nbsp;.&nbsp;$need_replace_str/"</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$file</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">done</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">done</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">"finished"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">cd</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">..</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">python3</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">setup.py</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">bdist_wheel</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">upload</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">-r</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">internal</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">echo</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">${CI_COMMIT_SHA}</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">noticeMail=$userMail</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">content="\nversion:</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$version\nproject:</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">$pkgName\ncommit:\nhttps://xxxxx/proto-center/commit/${CI_COMMIT_SHA}\n"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">curl</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">--location</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">--request</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">POST</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'https://xxxxx/webhookurl'</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">--header</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'Content-Type:&nbsp;application/json'</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">\</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">--data-raw</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">'{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"msg":&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"content":"'</span><span class="hljs-string" style="color: #98c379; line-height: 26px;">"${content}"</span><span class="hljs-string" style="color: #98c379; line-height: 26px;">'"<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}'</span><br></code></pre> </section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;"><p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">8️⃣ 构建完通知,在中央仓库的job里面可以添加钉钉,微信,slack这种类似的机器人🤖通知方便我们知道proto cicd流程的情况,可以带上我们的commit信息以及对应的版本。</p> </section></li></ul> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px; display: flex; flex-direction: column; justify-content: center; align-items: center;"><img src="https://cdn.hanyajun.com/20201125224142.png" alt style="display: block; margin: 0 auto; max-width: 100%;"></figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; border-bottom: 2px solid rgb(239, 112, 96); font-size: 1.3em;"><span class="prefix" style="display: none;"></span><span class="content" style="display: inline-block; font-weight: bold; background: rgb(239, 112, 96); color: #ffffff; padding: 3px 10px 1px; border-top-right-radius: 3px; border-top-left-radius: 3px; margin-right: 3px;">总结</span><span class="suffix"></span><span style="display: inline-block; vertical-align: bottom; border-bottom: 36px solid #efebe9; border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0; line-height: 26px; color: black;">总的来说,还有很多方案,每种方案都各有利弊,适合业务系统架构和公司组织机构的才是最好的方案,不过尽量通过工具来减少人肉的过程,提高效率。</p> <blockquote class="multiquote-1" data-tool="mdnice编辑器" style="border: none; display: block; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; border-left: 3px solid rgba(0, 0, 0, 0.4); color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; border-left-color: rgb(239, 112, 96); background: #fff9f9;"> <p style="font-size: 16px; padding-top: 8px; padding-bottom: 8px; margin: 0px; color: black; line-height: 26px;">参考链接</p> </blockquote> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;">https://eddycjy.com/posts/where-is-proto</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;">https://segmentfault.com/a/1190000022532645</section></li></ul> </section>

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3031 次点击  ∙  2 赞  
加入收藏 微博
被以下专栏收入,发现更多相似内容
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传