<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Bazel on 翟志军 Jack Zhai</title>
    <link>https://showme.codes/tags/bazel/</link>
    <description>Recent content in Bazel on 翟志军 Jack Zhai</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <copyright>showme.codes</copyright>
    <lastBuildDate>Sat, 20 Jan 2024 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://showme.codes/tags/bazel/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Setting up EKS with Bazel, Jsonnet and Terraform</title>
      <link>https://showme.codes/en/2024-01-20-eks-jsonnet-terraform-bazel/</link>
      <pubDate>Sat, 20 Jan 2024 00:00:00 +0000</pubDate>
      <guid>https://showme.codes/en/2024-01-20-eks-jsonnet-terraform-bazel/</guid>
      <description>&lt;h1 id=&#34;overview&#34;&gt;Overview&lt;/h1&gt;
&lt;p&gt;In this document, I&amp;rsquo;ll describe my solution from the following parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Part1 Architecture: describe the desired state of the architecture&lt;/li&gt;
&lt;li&gt;Part2 Implementation:
&lt;ul&gt;
&lt;li&gt;Code Structure Introduce&lt;/li&gt;
&lt;li&gt;How to Build it&lt;/li&gt;
&lt;li&gt;Deploy Nginx Controller using Helm&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&#34;part1-architecture&#34;&gt;Part1: Architecture&lt;/h1&gt;
&lt;p&gt;We assume that the project has a project named: health. Here&amp;rsquo;s the architecture graph, which draw by &lt;a href=&#34;https://excalidraw.com/&#34;&gt;Excalidraw&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://showme.codes/assets/images/eks-bazel-arch.png&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;network-architecture&#34;&gt;Network Architecture&lt;/h3&gt;
&lt;p&gt;I created 4 subnets that are evenly distributed to 2 Availability Zones. Each availability zone has 2 subnets, one is public subnet,and another one is private subnet.
The public subnet goes out through the Internet gateway and the private subnet goes out through the NAT gateway.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Bazel使用案例：构建Springboot工程</title>
      <link>https://showme.codes/zh-cn/2024-01-19-bazel-springboot/</link>
      <pubDate>Fri, 19 Jan 2024 00:00:00 +0000</pubDate>
      <guid>https://showme.codes/zh-cn/2024-01-19-bazel-springboot/</guid>
      <description>&lt;p&gt;本文是关于如何使用Bazel搭建Springboot 3.1.0工程（基于JDK17）。为什么使用Bazel，而不是使用Maven或者Gradle？可以看我之前关于Bazel的介绍文章。&lt;/p&gt;
&lt;h2 id=&#34;前期准备&#34;&gt;前期准备&lt;/h2&gt;
&lt;p&gt;在根目录加入&lt;code&gt;.bazelversion&lt;/code&gt;文件，并加入&lt;code&gt;6.2.0&lt;/code&gt;，指定当前工程使用的Bazel的版本。这样，Bazel命令自动使用该版本的Bazel进行构建。&lt;/p&gt;
&lt;p&gt;在根目录加入&lt;code&gt;.bazelrc&lt;/code&gt;文件，并指定构建和测试时使用JDK17，内容如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;build --java_language_version&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt; --java_runtime_version&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt; --tool_java_language_version&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt; --tool_java_runtime_version&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;  --java_language_version&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt; --java_runtime_version&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt; --tool_java_language_version&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt; --tool_java_runtime_version&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;17&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;外部依赖准备&#34;&gt;外部依赖准备&lt;/h2&gt;
&lt;p&gt;在根目录中创建以下两个文件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WORKSPACE：在Bazel中，所有的外部依赖统一定义WORKSPACE文件中；&lt;/li&gt;
&lt;li&gt;BUILD.bazel：内容留空即可，用于告诉Bazel当前目录也是一个Package。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bazel本身是支持多语言的。所以，我们需要特定语言的rule来帮助我们在WORKSPACE中定义外部依赖。&lt;/p&gt;
&lt;p&gt;对于Java工程，我们使用&lt;a href=&#34;https://github.com/bazelbuild/rules_jvm_external&#34;&gt;rules_jvm_external&lt;/a&gt;进行外部依赖的管理。它的使用步骤如下：&lt;/p&gt;
&lt;h3 id=&#34;步骤1在workspace中增加rules_jvm_external配置&#34;&gt;步骤1：在WORKSPACE中增加rules_jvm_external配置&lt;/h3&gt;
&lt;p&gt;以下配置指定了rules_jvm_external的下载位置，并进行rule的初始化：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@bazel_tools//tools/build_defs/repo:http.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;http_archive&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;RULES_JVM_EXTERNAL_TAG&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;4.5&amp;#34;&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;RULES_JVM_EXTERNAL_SHA&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;sha hash value&amp;gt;&amp;#34;&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;http_archive&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rules_jvm_external&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;strip_prefix&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rules_jvm_external-&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RULES_JVM_EXTERNAL_TAG&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;sha256&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RULES_JVM_EXTERNAL_SHA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://github.com/bazelbuild/rules_jvm_external/archive/&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.zip&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RULES_JVM_EXTERNAL_TAG&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@rules_jvm_external//:repositories.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rules_jvm_external_deps&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;rules_jvm_external_deps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@rules_jvm_external//:setup.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rules_jvm_external_setup&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;rules_jvm_external_setup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@rules_jvm_external//:defs.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;maven_install&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;maven_install&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;artifacts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;c1&#34;&gt;# The project&amp;#39;s dependencies&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;s2&#34;&gt;&amp;#34;junit:junit:4.12&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;s2&#34;&gt;&amp;#34;org.hamcrest:hamcrest-library:1.3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;n&#34;&gt;repositories&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;c1&#34;&gt;# Private repositories are supported through HTTP Basic auth  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;# &amp;#34;http://username:password@localhost:8081/artifactory/my-repository&amp;#34;,    &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;s2&#34;&gt;&amp;#34;https://maven.aliyun.com/repository/public&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;以上采用了非Bzlmod的管理rule。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Bazel作为构建工具之王，将会颠覆你对CI的认知</title>
      <link>https://showme.codes/zh-cn/2023-11-20-bazel-king-of-build-tool/</link>
      <pubDate>Mon, 20 Nov 2023 00:00:00 +0000</pubDate>
      <guid>https://showme.codes/zh-cn/2023-11-20-bazel-king-of-build-tool/</guid>
      <description>&lt;p&gt;说到构建工具，不同语言技术栈的人，想起的构建工具不同。&lt;/p&gt;
&lt;p&gt;Java程序员想到的是Maven，前端程序员想的是NPM或者Webpack、Android程序员想到的是Gradle、Rust程序想到的是Cargo、C++程序员想到的是Make等等。&lt;/p&gt;
&lt;p&gt;然而这些工具在Bazel面前，层次有些低。所以，我愿称Bazel是构建工具之王。&lt;/p&gt;
&lt;p&gt;P.S. Android平台的构建，2020年已经开始了迁移到Bazel的工作。 具体地址：https://blog.bazel.build/2020/11/12/aosp_migrating_to_bazel.html&lt;/p&gt;
&lt;h2 id=&#34;bazel介绍&#34;&gt;Bazel介绍&lt;/h2&gt;
&lt;p&gt;Bazel是Google在2015年开源的一款构建工具。&lt;/p&gt;
&lt;p&gt;目前使用Bazel的知名公司有：Esty、Canva、Databricks、Dropbox、Huawei、Line、LinkedIn、Stripe、Twitter、Tinder、Uber、VMware、Wix等。具体可以看：https://bazel.build/community/users 。&lt;/p&gt;
&lt;p&gt;其中Twitter是从自家的Pants迁移到的Bazel的，具体迁移过程介绍：https://opensourcelive.withgoogle.com/events/bazelcon2020/watch?talk=day1-talk2&lt;/p&gt;
&lt;p&gt;Facebook使用的是其自研的&lt;a href=&#34;https://engineering.fb.com/2023/04/06/open-source/buck2-open-source-large-scale-build-system/&#34;&gt;Buck2&lt;/a&gt;，但是，其与Bazel使用的是相同的远程执行的API。&lt;/p&gt;
&lt;p&gt;除了公司，某些著名的开源软件也使用Bazel构建，包括自动化测试领域的Selenium，AI领域的TensorFlow，容器编排领域的Kubernetes等。具体还有：https://bazel.build/community/users#open-source-projects-using-Bazel&lt;/p&gt;
&lt;p&gt;相对于其它构建工具，它的显著的特点有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持多语言；&lt;/li&gt;
&lt;li&gt;支持远程分布式构建；&lt;/li&gt;
&lt;li&gt;支持增量构建；&lt;/li&gt;
&lt;li&gt;支持强大的密闭性；&lt;/li&gt;
&lt;li&gt;支持构建缓存；&lt;/li&gt;
&lt;li&gt;支持并行构建。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;假设存在一个复杂的软件工程&#34;&gt;假设存在一个复杂的软件工程&lt;/h2&gt;
&lt;p&gt;假设存在一个软件工程中，它包含5部分：Web前端、Android端、Java后端、Go后端、嵌入式端。&lt;/p&gt;
&lt;p&gt;作为Java后端的程序员，他们修改了一个API。但是他作为个人，他无法预知到底发生了哪些影响。&lt;/p&gt;
&lt;p&gt;所以，他把这个问题交给了持续集成（CI），让它去发现集成问题。&lt;/p&gt;
&lt;p&gt;在过去很长一段时间里，行业里只有一种CI模式，我称之为传统的CI模式。&lt;/p&gt;
&lt;p&gt;殊不知，还有另一种模式。&lt;/p&gt;
&lt;h2 id=&#34;传统的ci模式&#34;&gt;传统的CI模式&lt;/h2&gt;
&lt;p&gt;目前行业里比较传统的CI架构，通常如下：
&lt;img loading=&#34;lazy&#34; src=&#34;https://showme.codes/assets/images/ci-traditional-architechure.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;在这样的架构下，实现CI的步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;开发人员提交代码；&lt;/li&gt;
&lt;li&gt;Gitlab检测到开发人员提交代码，然后触发Jenkins controller执行；&lt;/li&gt;
&lt;li&gt;Jenkins controller根据该代码仓库预先设计的pipeline执行；&lt;/li&gt;
&lt;li&gt;Jenkins controller根据pipeline中的任务所需要的构建环境，将任务分配给不同的Jenkins agent；&lt;/li&gt;
&lt;li&gt;在agent构建完成后，将制品release到制品仓库中。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果开发者希望验证自己写的代码，就必须将代码commit到Gitlab中。因为整个验证环境被定义在CI环境的Pipeline中。而且这个过程，越大的工程，集成速度越慢。开发者也无法在本地进行全量验证。&lt;/p&gt;
&lt;p&gt;作为Pipeline的维护者，他需要清楚知道哪些任务是可以并行执行的，并手工配置并行，这样才能加快构建速度。比如前端构建和后端构建可以并行进行。&lt;/p&gt;
&lt;p&gt;也就是说在传统的CI模式下，开发者的效率会随着软件的规模越大而降低。换句话，这样的模式，开发效率无法scale。&lt;/p&gt;
&lt;h2 id=&#34;案例&#34;&gt;案例&lt;/h2&gt;
&lt;p&gt;希望以下案例可以给你一个感性的认知。下图是Google在2010年到2015年的周commit数量。绿线代表commit总数，黄线是人数。我们取离我们最近的2015年的数据来讨论。2015年的代码量如下：
&lt;img loading=&#34;lazy&#34; src=&#34;https://showme.codes/assets/images/linesofcodeofgoogle.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;在这个代码量下，每周能达到300左右的commit。如下图：
&lt;img loading=&#34;lazy&#34; src=&#34;https://showme.codes/assets/images/google-commit-per-week.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;根据持续集成的原则，每一个commit都必须构建通过。20亿行代码一次全量构建需要多久？&lt;/p&gt;
&lt;p&gt;我们以一个开源项目作参考。apitable是一个开源的数据表格项目，它有200万左右的代码，全量构建一次需要20分钟左右。那么，根据不准确的类推，20亿行代码，全量构建一次需要：&lt;code&gt;20/2,000,000 * 2000,000,000=200,000,000&lt;/code&gt;分钟，也就是13天左右。&lt;/p&gt;
&lt;p&gt;在传统的CI模式下，是尽量避免执行全量构建这样庞大的代码量的。所以，传统CI模式下，通常是多仓库模式管理代码。&lt;/p&gt;
&lt;p&gt;那么Bazel呢？Bazel如果真要构建这样庞大的代码量，估计也够呛。但是由于Bazel天然支持并行构建、构建缓存和增量构建，所以，Bazel通常不会遇到真正意义的全量构建的情况。&lt;/p&gt;
&lt;h2 id=&#34;为什么其它公司不使用bazel&#34;&gt;为什么其它公司不使用Bazel&lt;/h2&gt;
&lt;p&gt;也许有人会问：为什么阿里2018年新增的代码行(&lt;a href=&#34;https://zhuanlan.zhihu.com/p/54435171&#34;&gt;https://zhuanlan.zhihu.com/p/54435171&lt;/a&gt;)就有12亿，不也没有使用Bazel吗？&lt;/p&gt;
&lt;p&gt;这个是一个好问题。&lt;/p&gt;
&lt;p&gt;但是，无法简单的回答这个问题，而是需要深入到各自组织内部才能分析清楚。个人觉得可以从以下维度分析：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在代码仓库上工作的人员的规模：同样的代码量，不同的组织需要不同数量的人维护；&lt;/li&gt;
&lt;li&gt;代码管理方式：阿里使用多仓库的管理办法，不需要统一的版本号；&lt;/li&gt;
&lt;li&gt;持续集成的程度不同：阿里可能不需要对每一个commit跑一次全量。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;为什么bazel会颠覆你对ci的认知&#34;&gt;为什么Bazel会颠覆你对CI的认知&lt;/h2&gt;
&lt;p&gt;Bazel是如何解决传统CI模式下开发效率无法scale的问题呢？其主要通过它的六个特性来解决。&lt;/p&gt;
&lt;p&gt;首先，Bazel支持远程分布式构建。&lt;/p&gt;
&lt;p&gt;在一个使用Bazel构建的仓库中，开发者写好代码后，不用commit代码到Git仓库，只要在本地命令行执行&lt;code&gt;bazel run --remote_executor=grpc://localhost:8980 //...&lt;/code&gt; ，代码仓库中所有构建和测试任务都将运行在远程执行服务器。远程执行服务器越多，构建速度越快。&lt;/p&gt;
&lt;p&gt;这一特性可以明显地提高开发者本地的开发效率。因为开发者在本地就可以执行全量构建和全量测试。&lt;/p&gt;
&lt;p&gt;传统CI模式下，无法提升开发者本地的开发效率。&lt;/p&gt;
&lt;p&gt;第二，Bazel支持增量构建和增量测试（精准测试）。&lt;/p&gt;
&lt;p&gt;开发者在本地执行build命令时，Bazel检测出修改了a.java文件，所以，Bazel只将构建a.java的任务及其相关的构建任务给远程执行服务器执行。这就是增量构建。&lt;/p&gt;
&lt;p&gt;如果开发者执行test命令，Bazel则能检测出被影响的测试，然后只运行这些测试。其实这就是精准测试了。在Bazel中，精准测试实现起来并不难。&lt;/p&gt;
&lt;p&gt;传统CI模式下，它是不关心增量构建和增量测试的。所以，每次运行都是全量。这是一种极大的浪费。&lt;/p&gt;</description>
    </item>
    <item>
      <title>基于Bazel &#43; SQLFluff实现SQL lint</title>
      <link>https://showme.codes/zh-cn/2023-04-17-sql-lint-by-bazel-sqlfluff/</link>
      <pubDate>Mon, 17 Apr 2023 00:00:00 +0000</pubDate>
      <guid>https://showme.codes/zh-cn/2023-04-17-sql-lint-by-bazel-sqlfluff/</guid>
      <description>&lt;h3 id=&#34;背景&#34;&gt;背景&lt;/h3&gt;
&lt;p&gt;SQL进行版本化控制后，我们希望为SQL加入lint步骤。这样做的好处是我们可以在真正执行SQL前发现问题。&lt;/p&gt;
&lt;p&gt;本文中，我们通过Bazel执行&lt;a href=&#34;https://github.com/sqlfluff/sqlfluff&#34;&gt;SQLFluff&lt;/a&gt;以实现SQL的lint。&lt;/p&gt;
&lt;p&gt;SQLFluff是一款使用Python语言使用的，支持SQL多方言的SQL lint工具。&lt;/p&gt;
&lt;p&gt;它的特点是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;支持多方言。如：Snowflake、PostgreSQL、ClickHouse。所有支持的方言列表：https://docs.sqlfluff.com/en/stable/dialects.html；&lt;/li&gt;
&lt;li&gt;可以输出正确的SQL，减少了我们手工修正SQL的工作；&lt;/li&gt;
&lt;li&gt;同时支持命令行方式使用和API调用方式。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;集成到cicd流水线中&#34;&gt;集成到CI/CD流水线中&lt;/h3&gt;
&lt;p&gt;在我看来，在CICD流水线中实现SQL lint有两种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方式一：在流水线中增加一个SQL lint步骤；&lt;/li&gt;
&lt;li&gt;方式二：将SQL lint的逻辑写在测试代码，执行测试步骤，就自动执行了SQL lint。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;方式二是我最爱，我会在本文最后讲原因。&lt;/p&gt;
&lt;h3 id=&#34;工程结构&#34;&gt;工程结构&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── BUILD.bazel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── WORKSPACE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── repository-hibernate-impl
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── BUILD.bazel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── src
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       ├── main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       │   └── sql
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       │       └── V1__runbook_table.sql
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│       └── &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│           └── python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│               ├── BUILD.bazel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│               ├── requirements_lock.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│               └── sql_test.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;步骤1-在workspace中增加python外部依赖&#34;&gt;步骤1: 在WORKSPACE中增加Python外部依赖&lt;/h3&gt;
&lt;p&gt;本文中我们使用的是Bazel 5.4.0，所以还在使用WORKSPACE定义外部依赖&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;http_archive&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rules_python&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;sha256&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;a644da969b6824cc87f8fe7b18101a8a6c57da5db39caa6566ec6109f37d2141&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;strip_prefix&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rules_python-0.20.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://github.com/bazelbuild/rules_python/releases/download/0.20.0/rules_python-0.20.0.tar.gz&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@rules_python//python:repositories.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;py_repositories&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;py_repositories&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@rules_python//python:repositories.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;python_register_toolchains&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;python_register_toolchains&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;python3_11&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;python_version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;3.11&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@python3_11//:defs.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;interpreter_3_11&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;interpreter&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@rules_python//python:pip.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;pip_parse&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Create a central repo that knows about the dependencies needed from  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# requirements_lock.txt.  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;pip_parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;pip_deps&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;python_interpreter_target&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;interpreter_3_11&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;requirements_lock&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;//repository-hibernate-impl/src/test/python:requirements_lock.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Load the starlark macro which will define your dependencies.  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;load&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;@pip_deps//:requirements.bzl&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;install_deps&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Call it to define repos for your requirements.  &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;install_deps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;步骤2-定义sqlfluff依赖&#34;&gt;步骤2: 定义SQLFluff依赖&lt;/h3&gt;
&lt;p&gt;requirements_lock.txt的内容如下：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
