Swift Packages and GitHub Actions

Swift Packages and GitHub Actions

Recently I was working on a matching library. Once I wrote the library, I wanted to have a CI that would verify the code on every push and pull request. There are services like Bitrise that can do this, but as I host the sources on GitHub, I decided to try built-in GitHub Actions.
To be honest, at first, I was skeptical. But to my surprise, GitHub Actions are great for Swift Packages. They are powerful, fast, and free for public repositories.
Let's see how to use them.

Adding GitHub Action to the project

Adding action to the project is very simple. On the main page of your repository:

1. Click on the Actions tab,

2. Click on the set up a workflow yourself,

3. In the editor, set the name of your action, and remember to add the .yml extension,

4. Write your action or copy & paste one of the actions below.

You can also use action suggested by GitHub. For Swift Packages, such action will build the package and run the tests.

Defining secret configuration values

Some actions might require configuration values. Some of those values might be secret, and we don't want to expose them in the action code. Fortunately, GitHub allows to easily define such secrets:

  1. Open repository settings,
  2. Select Secrets,
  3. Click on the New repository secret button,
  4. Provide the name and value.

That's it. Now, we can access the secret using the following syntax:

${{ secrets.SECRET_NAME }}

GitHub Actions helpful during Swift Packages development

Build package

This action builds a Swift Package:

name: Build Package

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: macos-11

    steps:
    - uses: actions/checkout@v2
        
    - name: Build
      run: swift build -v

Test package

This action builds a Swift Package and runs tests:

name: Test Package

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: macos-11

    steps:
    - uses: actions/checkout@v2
        
    - name: Build Package
      run: swift build -v
      
    - name: Run tests
      run: swift test -v

Test package, gather code coverage & upload report to codecov.io

This action builds a Swift Package and runs tests with code coverage enabled. Once tests are finished, the code coverage report is uploaded to codecov.io.

Token used by Codecov is defined as CODECOV_TOKEN  in the repository secrets.

Replace the {YOUR_PACKAGE_NAME} with the name of your package. For example, if the name of the package is gacalc, then replace the fragment {YOUR_PACKAGE_NAME}PackageTests with GacalcPackageTests.

Although the name of the package is all lowercased, the replaced name starts with uppercased first letter!
You can double check the name locally. Run the swift build command in the Terminal. Then open the .build folder: open .build. Inside the .build/debug folder you will find either {YOUR_PACKAGE_NAME}PackageTests.product or {YOUR_PACKAGE_NAME}PackageTests.xctest file.

name: Test Package

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: macos-11

    steps:
      - name: Get Sources
        uses: actions/checkout@v2

      - name: Build Package
        run: swift build -v

      - name: Run tests
        run: swift test --enable-code-coverage -v
      
      - name: Setup Xcode
        uses: maxim-lobanov/[email protected]
        with:
          xcode-version: "13.1"

      - name: Gather code coverage
        run: xcrun llvm-cov export -format="lcov" .build/debug/{YOUR_PACKAGE_NAME}PackageTests.xctest/Contents/MacOS/{YOUR_PACKAGE_NAME}PackageTests -instr-profile .build/debug/codecov/default.profdata > coverage_report.lcov

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v2
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: fail
          files: ./coverage_report.lcov
          verbose: true

When this action is executed for a pull request, the Codecov bot will add a comment with a new code coverage statistics:

Test package, gather code coverage & upload report to Code Climate

This action builds a Swift Package and runs tests with code coverage enabled. Once tests are finished, the code coverage report is uploaded to Code Climate.

Token used by Code Climate is defined as CODE_CLIMATE_TOKEN  in the repository secrets.

name: Test Package

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: macos-11

    steps:
      - name: Get Sources
        uses: actions/checkout@v2

      - name: Build Package
        run: swift build -v
        
      - name: Test & publish code coverage to Code Climate
        uses: paambaati/[email protected]
        env:
          CC_TEST_REPORTER_ID: ${{ secrets.CODE_CLIMATE_TOKEN }}
        with:
          coverageCommand: swift test --enable-code-coverage
          debug: true
          coverageLocations: |
            ${{github.workspace}}/.build/debug/codecov/*.json:lcov-json

Lint code using SwiftLint

This action lints the code using SwiftLint. Code linting for Swift Package can be done on macOS or Ubuntu environments.

Lint code using macOS as host machine:

name: Lint code

on:
  pull_request:
    paths:
      - '.github/workflows/codelint.yml'
      - '.swiftlint.yml'
      - '**/*.swift'

jobs:
  SwiftLint:
    runs-on: macos-11
    steps:
      - uses: actions/checkout@v1
      
      - name: Lint code using SwiftLint
        run: swiftlint lint --reporter github-actions-logging

Lint code using ubuntu as host machine:

name: Lint code

on:
  pull_request:
    paths:
      - '.github/workflows/codelint.yml'
      - '.swiftlint.yml'
      - '**/*.swift'

jobs:
  SwiftLint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      
      - name: Lint code using SwiftLint
        uses: norio-nomura/[email protected]

If there are any warnings or errors they will be added, as comments, to the PR's code:

That's it. As you can see, using GitHub Actions as CI for Swift Packages is very easy. I hope those that provided code snippets will help you configure your own Continues Integration process. If you want to see them in action,  check out this sample repository:

GitHub - mtynior/SwiftPackageWithGithubActionsAsCI: This repo shows how to set up and use GitHub Actions as a CI for Swift Packages
This repo shows how to set up and use GitHub Actions as a CI for Swift Packages - GitHub - mtynior/SwiftPackageWithGithubActionsAsCI: This repo shows how to set up and use GitHub Actions as a CI fo...

Comments

Anything interesting to share? Write a comment.