Issues will be collected using GitHub’s issue trackers, one for each HADES repo. Anyone can file an issue.

Assign an issue to a collaborator to indicate that person is working on it, or will be working on it shortly.

Issues can be labelled with the following labels (See also here):

Type of issue

  • bug Erroneous behavior that needs to be fixed. (Color #fc2929)
  • enhancement New functionality that could be added. (Color #84b6eb)
  • exploratory Changes that require some research first. (Color #fbca04)
  • question A questions that just needs an answer, not a change in code. (Color #cc317c)
  • duplicate Duplication of an existing issue. (Color #cccccc)

Issue collaboration

  • good first issue An issue that could be solved by someone new to the package. (Color #0052cc)
  • documentation Requires (re) writing of documentation, no coding. (Color #B7042F)
  • help wanted Will probably not be addressed by the package maintainer, but could be addressed by someone else. (Color #159818)


GitHub milestones should be used to indicate future versions, and link issues to those versions. Note that these milestones will also be reported in our roadmap dashboard, so they are a good way to keep HADES users informed on what will happen to their favorite package moving forward.

Some recommendations for milestones:

  • Use the name of the version as the milestone name (e.g. ‘v5.0.0’ for a next major release).
  • Provide a short description of the most important changes a user can expect in the release.
  • You can have (concurrent) miltestones for the next major and next minor release.
  • Collect all issues that will be addressed in the release under the milestone.
  • Ensure that issue titles are self-explanatory.

Pull requests

Before you do a pull request, you should always file an issue and make sure the package maintainer agrees that it’s a problem, and is happy with your basic proposal for fixing it. We don’t want you to spend a bunch of time on something that we don’t think is a good idea.

Additional requirements for pull requests:

  • Adhere to the Developer Guidelines posted here, as well as the OHDSI Code Style.

  • If possible, add unit tests for new functionality you add.

  • Restrict your pull request to solving the issue at hand. Do not try to ‘improve’ parts of the code that are not related to the issue. If you feel other parts of the code need better organization, create a separate issue for that.

  • Make sure you pass R check without errors and warnings before submitting.

  • Always target the develop branch, and make sure you are up-to-date with the develop branch.

Repo organization

All HADES repos follow the basic structure of R packages. See R packages for a thorough discussion on R packages.


We use R’s default package documentation features:

  • Functions and data are documented in a package manual. We use roxygen2 to document each function / data where they are defined in the code.

  • Detailed explanations of how to use a package are provides in vignettes.

The package manual and vignettes are available

  • Through R (e.g. by typing ?createPs)

  • As PDFs on the repo GitHub site.

  • In the package documentation website.

All of these should be generated when releasing a new version, as discussed in the Release Process section.

In addition, the file forms the main page of the package repo. This page has a standard structure, as for example can be seen here.

extras folder

The extras folder contains all files used by the package developer. These files will not be part of the package once installed. A required file in this folder is PackageMaintenance.R, which contains the code executed when releasing a package.

Unit tests

OHDSI unit testing for R follows the standard R practice using test_that: A folder named ‘tests’ is created in the root of the package, and this folder contains

  • A sub-folder called ’testthat`
  • A file called ‘testthat.R’
  • The file ‘testthat.R’ should have the following content:
library(<package name>)
test_check("<package name>")

The sub-folder ‘testthat’ should contain one or more R scripts whose file name starts with ‘test-’ (e.g. ‘test-connection.R’. Each file should contain one or more test_that blocks, for example

test_that("Function x returns 2", {
  expect_equal(x(), 2)

When unit tests are performed

Unit tests are triggered when

  • You manually perform a check of the R package (see the Build tab in R-Studio)

  • When Github Actions automatically builds the package after a push to the repository

You should only push changes to the GitHub repository if they pass R check locally.

Code coverage

We use codecov in combination with the covr package to measure which lines of codes are covered by at least one unit test.

Testing functions requiring database access

On the OHDSI Jenkins server there are 3 databases that can be accessed from within a unit test, for the 3 main platforms (SQL Server, Oracle, PostgreSQL). To access the databases locally, you’ll need to specify several environmental variables. These environmental variables should also be available when running tests using Github Actions.

Some example code in the DatabaseConnector package can be found here.

Coding guidelines

Some general coding guidelines:

Function calls must not have invisible side effects

When a user calls a function, the effect of that call should be aparent to the user. This means:

  • Do not call library or require in a function, as this changes the user’s search path.

  • Do not set options.

  • Do not write to files other than those specified by the user in the function call.

  • Do not use global variables.

Intead of using library, always explicitly reference the packge a function belongs to, for example SqlRender::translate().

Avoid unnecessary dependencies

Dependencies lead to instability. Only add dependencies to other packages if completely unavoidable.

We have more or less accepted we need to depend on the core tidyverse packages, so any of those packages are allowed.

Use named arguments

Except for very simple function calls (e.g. print(x)), use named arguments, for example:

sql <- SqlRender::translate(sql = "SELECT * FROM my_table;", targetDialect = "postgresql")

instead of

sql <- SqlRender::translate("SELECT * FROM my_table;", "postgresql")