Continuous Integration

Setting up CI

When initializing pre-commit in your repo with precommit::use_precommit(), you can specify the Continuous integration provider with ci = "native" if you want to use pre-commit.ci or ci = "gha" if you want to use GitHub Actions. For existing repos, use precommit::use_ci().

Pre-commit will run the hooks on all files, so instead of pushing, waiting and fixing issues locally, we recommend that you fix all problems before pushing by invoking pre-commit (roughly) the same way as it happens in the CI, which is described in the next section.

Emulate a CI run locally

In the CI run, a command roughly equivalent to the following will be ran from the command line:

pre-commit run --all-files

If you get an error and pre-commit is not on your $PATH (e.g. because you installed with precommit::install_precommit()), you can locate the executable from R with

precommit::path_pre_commit_exec()
#> "/usr/local/bin/pre-commit" 

And run the command in your bash terminal like this:

/usr/local/bin/pre-commit run --all-files

Then fix the problems, stage the files and re-try until the command succeeds without more errors.

Comparison

Next, we quickly introduce the two options. We recommend pre-commit.ci, but you might have to skip the roxygenize hook in the ci run under certain circumstances as explained below.

pre-commit.ci

Pros:

  • by the creator of pre-commit. Certain CI settings in .pre-commit-config.yaml are supported.
  • actively developed.
  • very fast.
  • will at some point also be supported for repos hosted outside of GitHub.
  • No maintenance effort for you.
  • No additional file in the repo.

Cons:

  • You need to authenticate the pre-commit.ci App in GitHub.

  • Limitations for the roxygenize hook:

    • {roxygen2} requires loading your package for the roxygenize hook, which means you must list all dependencies of the package explicitly in .pre-commit-config.yaml under id: roxygenize. You can generate the required code with precommit::snippet_generate('additional-deps-roxygenize'). This is also required to run the hook locally.
    • There is a timeout of 120s for building a hook environment, which might not be enough time to build the hook environment for the roxygenize hook (if you package has many dependencies). This holds for local and remote execution.
    • `System dependencies are not supported. In particular, since {roxygen2} requires loading your package for the roxygenize hook, this hook will fail if your package has system dependencies or any of your package’s dependencies has system dependencies that are not shipped with the package.
  • To overcome the above limitations, you can:

    • Disable the hook completely (by commenting out the respective lines in .pre-commit-config.yaml).
    • Use GitHub Actions as a CI provider instead with precommit::use_ci("gha").
    • Skip it on CI as described below
    ci:
        skip: [roxygenize]

Customization:

Please see the documentation of pre-commit.ci on whether or not to auto-fix problems as well as other configuration options.

GitHub Actions

Pros:

  • more control over environment, e.g. system dependencies.
  • No new authentication needed.
  • If your package has system dependencies and you want to use the roxygenize hook, you can install them.

Cons:

  • out-of-the-box action is in maintenance only mode and less feature complete than pre-commit.ci. For example, if your hooks fail on first attempt, the corrections are committed and pushed, but they won’t trigger a new CI and you can’t make them do it without exposing credentials. The only way is to close and re-open the PR.
  • No configuration options such as hook skipping supported that pre-commit.ci supports.
  • You need to maintain the workflow file with a lot of boilerplate code and when GitHub changes the syntax, you need to adapt it to prevent failing builds.
  • You’ll have one additional file per provider (e.g. GitHub, Gitlab).