A Quick guide to setting up the OpenTripPlanner project.
You need Git, Maven and Java(JDK) and an IDE installed on your computer. You IDE might have JDK and Maven embedded, if so you may skip step 3.
- Clone OpenTripPlanner from GitHub.
- Checkout the desired branch
git checkout dev-2.x
maven package- this will download all dependencies, build the project and run tests.
- Open the project in your IDE.
- Import the intellij-code-style.xml (IntelliJ IDE).
Working on OTP in an IDE
Most people writing or modifying OTP code use an Integrated Development Environment (IDE). Some of the most popular IDEs for Java development are IntelliJ IDEA, Eclipse, and NetBeans. All three of these environments are good for working on OTP. IntelliJ is used by most OTP developers, and the only IDE we support with a code style formatter. You may choose another IDE, but Maven and Git integration is a plus since OTP is under Git version control and build with Maven.
Many of the Core OTP developers use IntelliJ IDEA. It is an excellent IDE, and in my experience is quicker and more stable than the competition. IntelliJ IDEA is a commercial product, but there is an open source "community edition" that is completely sufficient for working on OTP.
Rather than using the version control support in my IDE, I usually find it more straightforward to clone the OTP GitHub repository manually (on the command line or using some other Git interface tool), then import the resulting local OTP repository into my IDE as a Maven project. The IDE should then take care of fetching all the libraries OTP depends on, based on the Maven project description (POM file) in the base of the OTP repository. This step can take a long time because it involves downloading a lot of JAR files.
When running your local copy of the OTP source within an IDE, all command line switches and
configuration options will be identical to the ones used when running the OTP JAR from the command
line (as described in the OpenTripPlanner Basic Tutorial and
configuration reference). The only difference is that you need to manually
specify the main class. When you run a JAR from the command line, the JVM automatically knows which
class contains the entry point into the program (the
main function), but in IDEs you must create
a "run configuration".
Both IntelliJ and Eclipse have "run" menus, from which you can select an option to edit the run configurations.
You want to create a configuration for a Java Application, specifying the main class
org.opentripplanner.standalone.OTPMain. Unlike on the command line, the arguments to the JVM and to the main class
you are running are specified separately. In the field for the VM options you'll want to put your maximum memory
-Xmx2G, or whatever limit you want to place on JVM memory usage). The rest of the parameters to OTP itself
will go in a different field with a name like "program arguments".
Contributing to the project
OpenTripPlanner is a community based open source project, and we welcome all who wish to contribute. There are several ways to get involved:
Join the developer mailing list
Fix typos and improve the documentation within the
/docsdirectory of the project (details below).
Submit patches. If you're not yet a committer, please provide patches as pull requests citing the relevant issue. Even when you do have push access to the repository, pull requests are a good way to get feedback on changes.
Branches and Branch Protection
As of January 2019, we have begun work on OTP 2.x and are using a Git branching model derived from Gitflow. All development will occur on the
dev-2.x branches. Only release commits setting the Maven artifact version to a non-snapshot number should be pushed to the
master branch of OTP. All other changes to master should result from fast-forward merges of a Github pull request from the
dev-1.x branch. In turn, all changes to
dev-1.x should result from a fast-forward merge of a Github pull request for a single feature, fix, or other change. These pull requests are subject to code review. We require two pull request approvals from OTP leadership committee members or designated code reviewers from two different organizations. We also have validation rules ensuring that the code compiles and all tests pass before pull requests can be merged.
dev-2.x branch is managed similarly to
dev-1.x but because it's rapidly changing experimental code worked on by relatively few people, we require only one pull request approval from a different organization than the author. Merges will not occur into
dev-2.x until that branch is sufficiently advanced and receives approval from the OTP project leadership committee.
Issues and commits
All commits should reference a specific issue number (this was formally decided in issue #175).
Simplify module X configuration #9999.
If no ticket exists for the feature or bug your code implements or fixes,
you should create a new ticket prior to checking in, or
ideally even prior to your development work since this provides a place to carry out implementation discussions (in the comments).
GitHub will automatically update issues when commits are merged in: if your commit message includes the text
fixes #123, it will automatically append your message as a comment on the isse and close it.
If you simply mention
#123 in your message, your message will be appended to the issue but it will remain open.
Many other expressions exist to close issues via commit messages. See the GitHub help page on this topic.
Unit tests using real OSM data
Sometimes it is useful to build a graph from actual OSM or GTFS data. Since building these graphs in a test can be quite slow they will be accepted in pull requests only if they conform to certain standards:
Use the smallest possible regional extract - the OSM file should not contain more than a few hundred ways. Use
osmium-extractto cut down a larger OSM file into a tiny subset of it.
Strip out any unneeded information by using the
osmium filter-tagsas describe in Preparing OSM
As a matter of policy, all new
methods, classes, and fields should include comments explaining what they are for and any other
pertinent information. For Java code, the comments should use the
JavaDoc conventions. It is best to provide
comments that not only explain what you did but also why you did it while providing some
context. Please avoid including trivial Javadoc or the empty Javadoc stubs added by IDEs, such as
@param annotations with no description.
Itinerary and API Snapshot Tests
To test the itinerary generation, and the API there are snapshot test which save the result of the
*.snap JSON-like files. These are stored in git so that it is possible to compare to
the expected result when running the tests.
If the snapshots need to be recreated than running
mvn clean -Pclean-test-snapshots will remove
*.snap files so that the next time the tests are run the snapshots will be recreated.
The updated files may be committed after checking that the changes in the files are expected.
OTP documentation is included directly in the OpenTripPlanner repository. This allows version control to be applied to documentation as well as program source code. All pull requests that change how OTP is used or configured should include changes to the documentation alongside code modifications.
The documentation files are in Markdown format and are in the
/docs directory under the root of
the project. On every push to the master branch the documentation will be rebuilt and deployed as
static pages to our subdomain of ReadTheDocs. MkDocs is
a Python program and should run on any major platform. See http://www.mkdocs.org/ for information on
how to install it and how to generate a live local preview of the documentation while you're working
on writing it.
The OTP REST API documentation is available online in the format of:
For example, for v2.1.0:
Adding new renderer is very easy. You just need to create new class (preferably in
org.opentripplanner.inspector package) which implements EdgeVertexRenderer. It is best if class
name ends with Rendered. To implement this interface you need to write three functions
getName. Both render functions accepts
EdgeVisualAttributes object in which
label of edge/vertex and color can be set. And both return
true if edge/vertex should be rendered
getName function should return short descriptive name of the class and will
be shown in layer chooser.
For examples how to write renderers you can look into example renderers which are all in
After your class is written you only need to add it to TileRenderManager:
//This is how Wheelchair renderer is added renderers.put("wheelchair", new EdgeVertexTileRenderer(new WheelchairEdgeRenderer()));
wheelchairis internal layer key and should consist of a-zA-Z and -.
By default all the tiles have cache headers to cache them for one hour. This can become problematic
if you are changing renderers a lot. To disable this change
//This lines CacheControl cc = new CacheControl(); cc.setMaxAge(3600); cc.setNoCache(false); //to this: CacheControl cc = new CacheControl(); cc.setNoCache(true);
Please use only ISO 8601 date format (YYYY-MM-DD) in documentation, comments, and throughout the project. This avoids the ambiguity that can result from differing local interpretations of date formats like 02/01/12.
The OTP code style is described on a separate style guide page.
The OpenTripPlanner project uses the Travis CI continuous integration system. Any time a change is pushed to the main OpenTripPlanner repository on GitHub, this server will compile and test the new code, providing feedback on the stability of the build.
The changelog file
is generated from the pull-request(PR) title using the
The workflow runs after the PR is merged, and it changes, commits and pushes the Changelog.md. A
secret personal access token is used to bypass the "Require PR with 2 approvals" rule. To exclude
a PR from the changelog add
[changelog skip] in the PR title.
How-to update the CHANGELOG_TOKEN
CHANGELOG_TOKEN is used by the changelog workflow. It contains a Personal Access Token. The token must be generated by a Repository Owner and have the following rights (Settings / Developer settings / Personal access tokens):
This section serves as a checklist for the person performing releases. Note that much of this mimics the actions taken by the Maven release plugin. Based on past experience, the Maven release plugin can fail at various points in the process leaving the repo in a confusing state. Taking each action manually is more tedious, but keeps eyes on each step and is less prone to failure. Releases are performed off the master branch, and are tagged with git annotated tags.
OpenTripPlanner is released as Maven artifacts to Maven Central. These include compiled and source code JARs as well as a "shaded" JAR containing all dependencies, allowing stand-alone usage. This release process is handled by the Sonatype Nexus Staging plugin, configured in the OpenTripPlanner POM.
We no longer trigger deployment of artifacts to Maven Central or deployment of documentation to AWS automatically in build scripts. These steps are prone to failure and require storing a lot of infrequently used secret information in the repo and environment variables on GitHub. Our releases are currently not very frequent so we just carry out these steps manually by following the checklist.
- Check that your local copy of the dev branch is up to date with no uncommitted changes
git checkout dev-2.x
git clean -df
- Verify that all dependencies in the POM are non-SNAPSHOT versions
- Lines should have been added or updated as each pull request was merged
- If you suspect any changes are not reflected in the Changelog, review the commit log and add any missing items
- Update the header at the top of the list from
x.y.z (current date)
- Check in any changes, and push to Github
- Check on GH Actions that the build is currently passing
- Switch to the HEAD of master branch, and ensure it's up to date with no uncommitted changes
git checkout master
git clean -df
- Merge the dev branch into master
git merge dev-2.x
- Bump the SNAPSHOT version in the POM to the release version
- Edit version in POM, removing SNAPSHOT and increasing version numbers as needed (following semantic versioning)
git add pom.xml
git commit -m "prepare release x.y.z"
- Run a test build of the release locally, without deploying it
mvn clean install site
installgoal will sign the Maven artifacts so you need the GPG signing certificate set up
- You can also use the
packagegoal instead of the
installgoal to avoid signing if you don't have the GPG certificate installed.
- All tests should pass
- This build will also create Enunciate API docs and Javadoc with the correct non-snapshot version number
- Deploy the documentation to AWS S3
- You have to do this right after the test release build to ensure the right version number in the docs
- You will need AWSCLI tools (
sudo pip install -U awscli)
- You will need AWS credentials with write access to the bucket
aws s3 cp --recursive target/site/apidocs s3://dev.opentripplanner.org/javadoc/x.y.z --acl public-read
aws s3 cp --recursive target/site/enunciate/apidocs s3://dev.opentripplanner.org/apidoc/x.y.z --acl public-read
- Check that docs are readable and show the correct version via the development documentation landing page.
- Finally, if everything looks good, tag and push this release to make it official
git tag -a vX.Y.Z -m "release X.Y.Z"
git push origin vX.Y.Z
- Note that only one commit may have a particular non-snapshot version in the POM (this is the commit that should be tagged as the release)
- Go to the GitHub tags page and use the
...button to mark the new tag as a release.
- Give the release a name like
v2.1.0 (March 2022)
- Optionally add a very condensed version of the changelog in the description box, with only the 5-10 most significant changes that might affect someone's choice to upgrade.
- Currently, pushing the tag does not trigger deployment of release Maven artifacts. This must be done manually. It can conceivably be configured to happen in the Actions scripts when any tag is pushed.
- Deploy the build artifacts to Maven Central and GitHub
- While still on the tag commit, run
mvn deployafter you have completed the local build as described above.
- This requires you to have the GPG keys and Maven repo credentials set up.
- Attach the JAR files produced in
/targetto the GitHub release page you just created.
- While still on the tag commit, run
- Set up next development iteration
- Add a new section header to
x.y+1.0-SNAPSHOT (in progress)
- Edit minor version in
git add pom.xml docs/Changelog.md
git commit -m "Prepare next development iteration x.y+1.0-SNAPSHOT"
- Add a new section header to
- Check that Maven artifact appears on Maven Central
- Directory listing of OTP releases on Maven Central
- It may take a while (half an hour) for releases to show up in the central repo after Travis uploads the artifacts
- Merge master back into dev (to sync up the Maven artifact version from the POM)
git checkout dev-2.x
git merge master
- Make sure the main documentation is built
- For some reason it doesn't always build automatically
- Go to builds of docs.opentripplanner.org
- Click "build version: latest"
- Email the OTP dev and users mailing lists
- Mention the new version number.
- Provide links to the new developer documentation.
- Provide links to the artifacts directory on Maven Central.
- Trigger build of latest OTP documentation on Readthedocs.
Maven release artifacts must be digitally signed to prove their origin. This is a safeguard against compromised code from a malicious third party being disguised as a trusted library.
The OTP artifact signing key was created by Conveyal. We export only that signing subkey, with our company's main key blanked out. Therefore, even if someone managed to acquire the decrypted key file and the associated GPG passphrase, they would not have the main key. We could deactivate the signing key and create a new one, without the main key being compromised.
OpenTripPlanner's POM is set up to sign artifacts in the verify phase, which means signing will happen for the
deploy targets, but not the
package target. When performing a local test build, if you do
mvn clean install site it will test the signing process.
If you do not have the certificate installed, you can instead to
mvn clean package site to bypass signing, but this
provides less certainty that everything is set up correctly for the CI-driven final release.