跳至主要内容

从 CircleCI 迁移到 GitHub Actions

GitHub Actions 和 CircleCI 在配置方面有很多相似之处,这使得迁移到 GitHub Actions 相对简单。

简介

CircleCI 和 GitHub Actions 都允许您创建自动构建、测试、发布、发布和部署代码的工作流程。CircleCI 和 GitHub Actions 在工作流程配置方面有一些相似之处。

  • 工作流程配置文件是用 YAML 编写的,并存储在存储库中。
  • 工作流程包含一个或多个作业。
  • 作业包含一个或多个步骤或单个命令。
  • 步骤或任务可以重复使用并与社区共享。

有关更多信息,请参阅“了解 GitHub Actions”。

主要区别

从 CircleCI 迁移时,请考虑以下差异。

  • CircleCI 的自动测试并行性会根据用户指定的规则或历史计时信息自动对测试进行分组。此功能未内置在 GitHub Actions 中。
  • 在 Docker 容器中执行的操作对权限问题很敏感,因为容器对用户的映射不同。您可以通过在您的 Dockerfile 中不使用 USER 指令来避免许多这些问题。有关 GitHub 托管运行器上的 Docker 文件系统的更多信息,请参阅“使用 GitHub 托管运行器”。

迁移工作流程和作业

CircleCI 在 config.yml 文件中定义 workflows,这使您可以配置多个工作流程。GitHub 每个工作流程需要一个工作流程文件,因此不需要您声明 workflows。您需要为 config.yml 中配置的每个工作流程创建一个新的工作流程文件。

CircleCI 和 GitHub Actions 都使用类似的语法在配置文件中配置 jobs。如果您使用 CircleCI 工作流程中的 requires 配置作业之间的任何依赖关系,则可以使用等效的 GitHub Actions needs 语法。有关更多信息,请参阅“GitHub Actions 的工作流程语法”。

将 orbs 迁移到操作

CircleCI 和 GitHub Actions 都提供了一种在工作流中重用和共享任务的机制。CircleCI 使用名为 orbs 的概念,用 YAML 编写,提供可以在工作流中重用的任务。GitHub Actions 拥有功能强大且灵活的可重用组件,称为 actions,可以使用 JavaScript 文件或 Docker 镜像构建。您可以通过编写与您的仓库以任何您想要的方式交互的自定义代码来创建 actions,包括与 GitHub 的 API 和任何公开可用的第三方 API 集成。例如,一个 action 可以发布 npm 模块,在创建紧急问题时发送短信提醒,或部署生产就绪代码。有关更多信息,请参阅 "创建 actions"。

CircleCI 可以使用 YAML 锚点和别名重用工作流的部分内容。GitHub Actions 支持使用矩阵来满足最常见的可重用性需求。有关矩阵的更多信息,请参阅 "在工作中使用矩阵"。

使用 Docker 镜像

CircleCI 和 GitHub Actions 都支持在 Docker 镜像中运行步骤。

CircleCI 提供了一组预构建的镜像,其中包含常见的依赖项。这些镜像将 USER 设置为 circleci,这会导致权限与 GitHub Actions 冲突。

我们建议您在迁移到 GitHub Actions 时,不要再使用 CircleCI 的预构建镜像。在许多情况下,您可以使用 actions 来安装您需要的额外依赖项。

有关 Docker 文件系统的更多信息,请参阅 "使用 GitHub 托管的运行器"。

有关 GitHub 托管的运行器镜像上可用的工具和包的更多信息,请参阅 "使用 GitHub 托管的运行器"。

使用变量和密钥

CircleCI 和 GitHub Actions 支持在配置文件中设置变量,并使用 CircleCI 或 GitHub UI 创建密钥。

有关更多信息,请参阅 "变量" 和 "在 GitHub Actions 中使用密钥"。

缓存

CircleCI 和 GitHub Actions 提供了一种在配置文件中手动缓存文件的方法。

以下是每个系统语法的示例。

CircleCI 缓存语法

- restore_cache:
    keys:
      - v1-npm-deps-{{ checksum "package-lock.json" }}
      - v1-npm-deps-

GitHub Actions 缓存语法

- name: Cache node modules
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: v1-npm-deps-${{ hashFiles('**/package-lock.json') }}
    restore-keys: v1-npm-deps-

GitHub Actions 没有等同于 CircleCI 的 Docker 层缓存 (DLC) 的功能。

在作业之间持久化数据

CircleCI 和 GitHub Actions 都提供了在作业之间持久化数据的机制。

以下是 CircleCI 和 GitHub Actions 配置语法中的示例。

CircleCI 在作业之间持久化数据的语法

- persist_to_workspace:
    root: workspace
    paths:
      - math-homework.txt

...

- attach_workspace:
    at: /tmp/workspace

GitHub Actions 在作业之间持久化数据的语法

- name: Upload math result for job 1
  uses: actions/upload-artifact@v4
  with:
    name: homework
    path: math-homework.txt

...

- name: Download math result for job 1
  uses: actions/download-artifact@v4
  with:
    name: homework

有关更多信息,请参阅 "将工作流数据存储为工件”。

使用数据库和服务容器

这两个系统都允许您包含用于数据库、缓存或其他依赖项的额外容器。

在 CircleCI 中,config.yaml 中列出的第一个镜像是用于运行命令的主要镜像。GitHub Actions 使用显式部分:使用 container 表示主容器,并在 services 中列出其他容器。

以下是 CircleCI 和 GitHub Actions 配置语法中的示例。

CircleCI 使用数据库和服务容器的语法

---
version: 2.1

jobs:

  ruby-26:
    docker:
      - image: circleci/ruby:2.6.3-node-browsers-legacy
        environment:
          PGHOST: localhost
          PGUSER: administrate
          RAILS_ENV: test
      - image: postgres:10.1-alpine
        environment:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby26
          POSTGRES_PASSWORD: ""

    working_directory: ~/administrate

    steps:
      - checkout

      # Bundle install dependencies
      - run: bundle install --path vendor/bundle

      # Wait for DB
      - run: dockerize -wait tcp://127.0.0.1:5432 -timeout 1m

      # Setup the environment
      - run: cp .sample.env .env

      # Setup the database
      - run: bundle exec rake db:setup

      # Run the tests
      - run: bundle exec rake

workflows:
  version: 2
  build:
    jobs:
      - ruby-26
...

- attach_workspace:
    at: /tmp/workspace

GitHub Actions 使用数据库和服务容器的语法

name: Containers

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest
    container: circleci/ruby:2.6.3-node-browsers-legacy

    env:
      PGHOST: postgres
      PGUSER: administrate
      RAILS_ENV: test

    services:
      postgres:
        image: postgres:10.1-alpine
        env:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby25
          POSTGRES_PASSWORD: ""
        ports:
          - 5432:5432
        # Add a health check
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
      # This Docker file changes sets USER to circleci instead of using the default user, so we need to update file permissions for this image to work on GH Actions.
      # See https://docs.github.com/actions/using-github-hosted-runners/about-github-hosted-runners#docker-container-filesystem

      - name: Setup file system permissions
        run: sudo chmod -R 777 $GITHUB_WORKSPACE /github /__w/_temp
      - uses: actions/checkout@v4
      - name: Install dependencies
        run: bundle install --path vendor/bundle
      - name: Setup environment configuration
        run: cp .sample.env .env
      - name: Setup database
        run: bundle exec rake db:setup
      - name: Run tests
        run: bundle exec rake

有关更多信息,请参阅 "关于服务容器”。

完整示例

以下是一个现实世界的示例。左侧显示了 thoughtbot/administrator 存储库的实际 CircleCI config.yml。右侧显示了 GitHub Actions 的等效内容。

CircleCI 的完整示例

---
version: 2.1

commands:
  shared_steps:
    steps:
      - checkout

      # Restore Cached Dependencies
      - restore_cache:
          name: Restore bundle cache
          key: administrate-{{ checksum "Gemfile.lock" }}

      # Bundle install dependencies
      - run: bundle install --path vendor/bundle

      # Cache Dependencies
      - save_cache:
          name: Store bundle cache
          key: administrate-{{ checksum "Gemfile.lock" }}
          paths:
            - vendor/bundle

      # Wait for DB
      - run: dockerize -wait tcp://127.0.0.1:5432 -timeout 1m

      # Setup the environment
      - run: cp .sample.env .env

      # Setup the database
      - run: bundle exec rake db:setup

      # Run the tests
      - run: bundle exec rake

default_job: &default_job
  working_directory: ~/administrate
  steps:
    - shared_steps
    # Run the tests against multiple versions of Rails
    - run: bundle exec appraisal install
    - run: bundle exec appraisal rake

jobs:
  ruby-25:
    <<: *default_job
    docker:
      - image: circleci/ruby:2.5.0-node-browsers
        environment:
          PGHOST: localhost
          PGUSER: administrate
          RAILS_ENV: test
      - image: postgres:10.1-alpine
        environment:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby25
          POSTGRES_PASSWORD: ""

  ruby-26:
    <<: *default_job
    docker:
      - image: circleci/ruby:2.6.3-node-browsers-legacy
        environment:
          PGHOST: localhost
          PGUSER: administrate
          RAILS_ENV: test
      - image: postgres:10.1-alpine
        environment:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby26
          POSTGRES_PASSWORD: ""

workflows:
  version: 2
  multiple-rubies:
    jobs:
      - ruby-26
      - ruby-25

GitHub Actions 的完整示例

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# GitHub recommends pinning actions to a commit SHA.
# To get a newer version, you will need to update the SHA.
# You can also reference a tag or branch, but the action may change without warning.

name: Containers

on: [push]

jobs:
  build:

    strategy:
      matrix:
        ruby: ['2.5', '2.6.3']

    runs-on: ubuntu-latest

    env:
      PGHOST: localhost
      PGUSER: administrate
      RAILS_ENV: test

    services:
      postgres:
        image: postgres:10.1-alpine
        env:
          POSTGRES_USER: administrate
          POSTGRES_DB: ruby25
          POSTGRES_PASSWORD: ""
        ports:
          - 5432:5432
        # Add a health check
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5

    steps:
      - uses: actions/checkout@v4
      - name: Setup Ruby
        uses: eregon/use-ruby-action@ec02537da5712d66d4d50a0f33b7eb52773b5ed1
        with:
          ruby-version: ${{ matrix.ruby }}
      - name: Cache dependencies
        uses: actions/cache@v3
        with:
          path: vendor/bundle
          key: administrate-${{ matrix.image }}-${{ hashFiles('Gemfile.lock') }}
      - name: Install postgres headers
        run: |
          sudo apt-get update
          sudo apt-get install libpq-dev
      - name: Install dependencies
        run: bundle install --path vendor/bundle
      - name: Setup environment configuration
        run: cp .sample.env .env
      - name: Setup database
        run: bundle exec rake db:setup
      - name: Run tests
        run: bundle exec rake
      - name: Install appraisal
        run: bundle exec appraisal install
      - name: Run appraisal
        run: bundle exec appraisal rake