美文网首页
一份送给iOS开发人员不得不看一个知识

一份送给iOS开发人员不得不看一个知识

作者: iOS祈峰 | 来源:发表于2021-11-08 22:02 被阅读0次

    前言

    学如逆水行舟,不进则退。共勉!

    昨天在腾讯课堂听了一个关于iOS的直播课堂,是一名叫做cat的老师吧,印象还是比较深刻的。主要内容是讲使用xcconfig更改应用设置,听完这堂课了,基本上掌握了:

    1. xcconfig解析
    2. 通过xcconfig配置多个开发环境
    3. 通过xcconfig构建LLVM小工具
    4. 通过代码访问xcconfig

    讲得还是非常不错的,然后今天主要是给大家分享一份cat老师整理的一份Github Action,我觉得还是非常有用的。也希望大家给我点点赞点点关注支持一下。tip:老师也经常逛掘金,希望老师能看到,嘿嘿。

    一、GitHub Actions

    GitHub Actions是一个由事件驱动的自动化平台,通过设置触发条件,在某些事件发生时自动运行指定的操作。

    换句话讲, GitHub Actions 不仅允许开发人员在平台上托管代码,还可以操作它。通过 GitHub Actions ,我们能够自动化一个跨团队、手动且容易出错的流程,可以使每个团队能够独立运作,有助于提高生产力。

    GitHub Actions 的一个常见实用场景就是进行自动化的持续集成和部署。持续集成由很多操作组成,比如拉取代码、推送代码、运行测试,发布到第三方服务等等。在这个过程中 GitHub 把开发者可以对代码执行的操作包装成了一个个功能模块,就叫action。开发者可以将多个action组合成一个workflow工作流程。

    例如,当指定发生拉取或推送操作时,触发 GitHub CI服务器。执行由一个或多个action组合到一起的workflow工作流程。

    image.png

    在GitHub Actions中,通过workflow工作流程指定需要运行的action,以及执行它们的触发器条件。 workflow定义在当前操作的git仓库中的.github/ workflow目录中,可以定义一个或多个 workflow。 workflow文件必须使用YAML语法,必须以.yml或.yaml作为文件扩展名。

    每个action都是一个独立的功能,存放到指定的Actions仓库中。意味着如果你需要功能,不必自己写,可以直接引用他人写好的action。 Github 自己维护了一个marketplace。还有一个awesome action,也可以找到一些好用的action。

    要引用一个action,可使用 userName/repoName的引用action。 比如, actions/checkout就表示引用官方action仓库中的 github.com/actions/checkout 这个仓库,作用是checkout当前的使用的GitHub托管的服务器,以便workflow可以访问它。

    actions/checkout@25a956c#指向一个 commit
    actions/checkout@v1     #指向一个标签
    actions/checkout@main    #指向一个分支
    复制代码
    

    如果,要访问使用非官方提供的action,通过userName/repoName:

    lukka/run-vcpkg@v6
    lukka/run-cmake@v3
    复制代码
    
    image.png

    接下来,我们来实际分析一个workflow。

    Kingfisher

    在 Kingfisher 的.github/workflows目录中有一个 build.yaml。专门用来通过fastlane的scan或者gym来进行编译和测试示例工程的。

    #1
    name:build
    
    #2
    on: [push, pull_request]
    
    #3
    jobs:
    run-test:
    
    # 4 
    runs-on: macOS-latest 
    
    # 5 
    strategy:
    matrix:
    destination: [
    'macOS', 
    'iOS Simulator,name=iPhone 8', 
    'tvOS Simulator,name=Apple TV',  
    'watchOS Simulator,name=Apple Watch Series 5 - 40mm' 
    ] 
    swift-version: [5.0]
    
    # 6 
    steps: 
    # 7 
    - uses: actions/checkout@v1 
    - uses: actions/cache@v1 # 8 
    id: bundler-cache # 9 
    with: # 10 
    path: vendor/bundle  
    key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} 
    restore-keys: |
    ${{ runner.os }}-gems- 
    
    # 11 
    - name: Bundle setup
    run: bundle config path vendor/bundle  
    
    - name: Bundle install 
    if: steps.bundler-cache.outputs.cache-hit != 'true' # 12
    run: bundle install --jobs 4 --retry 3 
    - name: Run tests
    env: # 13 
    DESTINATION: platform=${{ matrix.destination }} 
    SWIFT_VERSION: ${{ matrix.swift-version }} 
    run: bundle exec fastlane test_ci # 14
    复制代码
    

    我们一个步骤一个步骤的来分析:

    1. name: workflow的名称。当前 workflow名称被设置为build;
    2. on必填。用来指定触发条件,触发条件被触发开始执行。当前workflow被触发的条件有两个:push和 pull_request 。当发生push或pull操作时,触发该 workflow ;
    3. jobs指定当前的workflow再被触发时可以运行的一项或多项jobs;
    4. jobs.<job_id>.runs-on必填。指定要运行job的服务器类型。当前的workflow指定的服务器器为 GitHub提供的 macOS-latest;
    5. jobs.<job_id>.strategy.matrix:构建矩阵,当前workflow中有两个key:
    • destination 指明bundle的缓存key、fastlane的产物类型:
    • swift-version用的Swift版本。
    1. steps指明当前job包含的具体步骤:

    i. 第一步是运行github提供的 checkout action 。将当前仓库checkout到当前的服务器;

    ii. 第二步,配置fastlane需要的ruby环境。使用官方提供 actions/cache来缓存 actions/cache。

    iii.jobs.<job_id>.steps[*].id,当前step的唯一标识。用于在上下文环境中引用该step;

    iv.jobs.<job_id>.steps[*].with :指明当前action序言的输入参数,使用map。每个输入参数都是一个键/值对。如果当前输入的不是action需要的输入参数,那么这些参数将被设置为环境变量。该变量的会自动加上前缀 INPUT_ ,并转换为大写;

    v.当我们不需要action时,可以使用name表明步骤的名称和run指明步骤执行时构建服务器将运行的命令,来自定义一个step;

    vi.jobs.<job_id>.steps[*].if,通过if:表达式,判断当前是否满足step运行需要的信息;

    vii.jobs.<job_id>.steps[*].env,用于设置当前step的环境中变量;

    viii:最后,通过fastlane执行在fastlane目录中的Fastfile定义的test_ci lane 。

    接下来Github Action YAML语法细节部分。

    二、Github Actions YAML语法详解

    我们还是以 Kingfisher中出现的语法为准。

    name

    workflow 的名称。Github在仓库的Action页面上显示该仓库使用workflow的名称。如果省略name,Github将其设置为相对于仓库根目录的工作流程文件路径;

    [图片上传失败...(image-6ed44a-1636379475823)]

    on

    用来指定触发条件,触发条件被触发开始执行

    可以提供单一触发条件string、一组触发条件array、不同事件类型types的一组条件array或map,指明workflow的运行条件,或将workflow的执行限于特定文件、标记或分值更改。

    jobs

    指定当前的workflow再被触发时可以运行的一项或多项jobs。

    jobs默认是并行运行。要按顺序运行jobs,可以使用 <job_id>needs关键词在job定义依赖项。每个job在runs-on指定的服务器环境中运行。

    defaults和 jobs.<job_id>.defaults

    设置将应用到workflow中所有job或指定job的默认设置。在job中定义的默认设置将覆盖在workflow中定义的同名默认设置。

    defaults.run和 jobs.<job_id>.defaults.run

    为workflow中的所有run步骤提供默认的shell和 working-directory选项。也可以设置只可用于job默认设置。

    jobs.<job_id>.runs-on必填

    指定要运行job的服务器类型。

    服务器可以是Github托管的服务器器或自托管的服务器器:

    [图片上传失败...(image-fe6aad-1636379475823)]

    **jobs.<job_id>.strategy.matrix **

    如果我们需要当前的workflow中的运行的job、执行的action或者执行的命令运行到多个操作系统、平台和语言,进行多个组合运行测试。

    同时不想创建多个相同的操作,来区别进行区分。

    这个时候可以使用构建矩阵:

    1. 构建矩阵是使用strategy关键字创建的,接受构建选项作为数组。构建矩阵在每次workflow运行时最多可生成256个jobs。此限制也适用于自托管服务器;
    2. 在matrix中定义的每个选项都有键和值。定义的键将成为matrix上下文中的属性,可以再workflow文件的其他区域中引用该属性。例如,如果定义包含操作系统创建一个job。定义的第一个选项将是工作流程中运行的第一个job;

    step

    指明当前job包含的具体步骤。

    step可以运行命令、运行设置任务,或者运行action等等。每个step在服务器环境中以其自己的进程运行,且可以访问工作区和文件系统。

    因为step以自己的进程运行,所以step之间不会保留环境变量的更改。在workflow的使用限制之内可运行无限数量的steps。接下来,开始执行具体操作;

    jobs.<job_id>.steps[*].uses

    指定当前step中要运行的action。action是一种可重复使用的代码单位;

    jobs.<job_id>.steps[*].id

    当前step的唯一标识。用于在上下文环境中引用该step;

    jobs.<job_id>.steps[*].with

    指明当前的action序言的输入参数,使用map

    每个输入参数都是一个键/值对。如果当前输入的不是action需要的参数,那么这些参数将被设置为环境变量。该变量的会自动加上前缀INPUT_ ,并转换为大写;

    jobs.<job_id>.steps[*].if

    通过if:表达式,判断当前是否满足step运行需要的信息。

    • 表达式可以是文字值、上下文引用或函数的任意组合。以使用运算符组合文字、上下文引用和函数。表达式通常在工作流程文件中与条件性if关键词一起用来确定步骤是否应该运行。当if条件为true时,步骤将会运行;
    • 在if条件下使用表达式时,可以省略表达式语法 (<math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">)</mo><mtext>,因为</mtext><mi>G</mi><mi>i</mi><mi>t</mi><mi>h</mi><mi>u</mi><mi>b</mi><mtext>会自动将</mtext><mi>i</mi><mi>f</mi><mtext>条件作为表达式求值,除非表达式包含任何运算符。如果表达式包含任何运算符,则表达式必须包含在</mtext></mrow><annotation encoding="application/x-tex">{{ }}),因为Github会自动将if条件作为表达式求值,除非表达式包含任何运算符。如果表达式包含任何运算符,则表达式必须包含在 {{ }}</annotation></semantics></math>),因为Github会自动将if条件作为表达式求值,除非表达式包含任何运算符。如果表达式包含任何运算符,则表达式必须包含在 内,以明确标记它进行计算。

    jobs.<job_id>.steps[*].env ̵ env ޾ jobs.<job_id>.env

    用于设置当前 workflow 、单个job或者单个step的环境中变量。当多个环境使用相同的名称定义时,Github有一套覆盖规则。

    • step中有定义的环境变量在step执行时将覆盖名称相同的job和workflow变量;
    • job定义的变量在job执行时将覆盖名称相同的workflow变量。

    三、 Ruby Gems缓存

    当执行bundle install时,需要根据Gemfile或者 Gemfile.lock下载指定的ruby gems。当在Github CI进行构建时,我们可以把需要下载的ruby gems通过使用 Github action缓存到当前的CI服务器,这样进行构建时,就能更快的加载我们需要的gems。

    Github一共提供了两种action可以帮助我们完成缓存操作:

    • actions/cache :最流行的缓存Ruby gem方案,仅缓存;
    • ruby/setup-ruby :可以安装指定版本的Ruby并且使用bundler缓存Ruby gem。

    ** actions/cache **

    actions/cache 将ruby gems保存到缓存中并在下一下CI构建期间恢复它。如果要指定Ruby版本,需要在当前的仓库目录,创建一个 .ruby-version 文件,将依赖的ruby版本写入该文

    2.7.0
    
    

    我们再来看一下 Kingfisher中的设置:

    # 1
    - uses: actions/cache@v1 
    id: bundler-cache
    with: 
    path: vendor/bundle # 2
    key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }} # 3 
    restore-keys: 
    | ${{ runner.os }}-gems- # 4
    # 5
    - name: Bundle setup 
    run: bundle config path vendor/bundle
    - name: Bundle install 
    if: steps.bundler-cache.outputs.cache-hit != 'true' # 6
    run: bundle install --jobs 4 --retry 3
    
    
    1. 对于 actions/cache的v1版本,仅支持单个路径,它必须是一个目录。不能缓存单个文件。使用 actions/cache的v2版本,可以指定单个路径,也可以在单独的行上添加多个路径;
    2. 输入参数path必要。指定缓存或还原的文件路径。路径可以是绝对路径或相对于工作目录的路径。当前是 vendor/bundle ;
    3. 输入参数key,必要。根据当前的操作系统和 Gemfile.lock文件哈希表达式生成缓存key作为搜索缓存的键。当操作系统或者 Gemfile.lock发生改变时,重新生成key值;当key匹配现有缓存时,被称为缓存命中,并且操作会将缓存的文件还原到path目录;
    4. restore-keys :可选。key没有发生缓存命中时用于查找缓存的其他密钥顺序列表;

    i. 如果提供restore-keys,actions/cache将按顺序搜索与 restore-keys列表匹配的任何缓存; ii. 当精确匹配时,操作会将缓存中的文件恢复至设置path的目录; iii.如果没有精确匹配,操作将会搜索恢复键值的部分匹配。当操作找到部分匹配时,最近的缓存将恢复至设置path的目录 5. bundle config path vendor/bundle配置bundle,将需要的ruby gems安装到 vendor/bundle目录 6. cache-hit是actions/cache的输出参数。获取缓存命中的结果。

    i.当key不匹配现有缓存时,则被称为缓存错过,在job成功完成时将创建一个新缓存。发生缓存错过时,操作将搜索restore-keys 设置的替代键值。 7. --jobs 4 --retry 3 ,并行安装 ruby gems 。如果当前有网络问题,将尝试3次。

    ** ruby/setup-ruby**

    如果使用 ruby/setup-ruby来管理gem缓存和ruby版本就更加直观和简洁。首先,在Github中forkKingfisher到自己的仓库。把 .github/workflows中的build.ymal修改为:

    name: build
    
    on: [push, pull_request]
    
    jobs: 
    run-test: 
    runs-on: macOS-latest 
    strategy: 
    matrix:
    destination: [ 
    'macOS',  
    'iOS Simulator,name=iPhone 8',  
    'tvOS Simulator,name=Apple TV',  
    'watchOS Simulator,name=Apple Watch Series 5 - 40mm' 
    ] 
    swift-version: [5.0]
    steps: 
    - uses: actions/checkout@v1
    - uses: ruby/setup-ruby@v1 
    with: 
    ruby-version: 2.7
    bundler-cache: true true 
    
    name: Run tests
    env: 
    DESTINATION: platform=${{ matrix.destination }}
    SWIFT_VERSION: ${{ matrix.swift-version }} 
    run: bundle exec fastlane test_ci
    
    

    接下来,将修改的代码push到自己的仓库中。此时已经触发Github CI服务器,开始执行workflow:

    image.png

    一共有四个任务,分别对应看,我们配置在构建矩阵中的参数。

    image.png

    实际执行的命令信息;

    image.png

    可以看到,仅仅1需要设置 bundler-cache: true。同时不再需要文件去指定ruby版本。相对来说就可以避免手动设置缓存时带来的问题。

    四、 ̵What is YAML?

    YAML是一种易于理解的数据序列化语言,是一种面向数据的语言,通常用于创建配置/描述文件。与JSON相比于YAML更强调数据序列化、可视化、可读性和层次性。

    JSON的语法本身是 YAML1.2版的子集。换句话讲, YAML 是JSON的严格超集,它可以做的一切,甚至更多。和python一样, YAML 使用缩进来表示嵌套,我们可以使用空格作为缩进,但不能使用Tab,制表符缩进是被禁止的。并且换行符和缩进在 YAML 中具有某种含义。不像JSON,后者使用方括号和大括号。但是,json格式在 YAML 中是有效的。

    YAML 文件使用.yml或.yaml作为扩展名。

    ** YAML 快速入门**

    image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png image.png

    END

    不知各位读者看完觉得怎么样,有没有帮助?有没有启发了?或者有什么其他想法都可以在留言区留言。

    最后的话就是如果你也想听公开课,关注我主页。

    相关文章

      网友评论

          本文标题:一份送给iOS开发人员不得不看一个知识

          本文链接:https://www.haomeiwen.com/subject/zmupzltx.html