This repository is a monorepo (in other words, it contains multiple applications and packages that are interdependent) managed by Turborepo.
The relevant applications (in the apps directory) are:
Application | Description |
---|---|
ramp-download | UNNEEDED NextJS based application for downloading contet from the Ramp API and storing it in a local database when ramp-refresh did not work. |
ramp-info | OBSOLETE Application originally intended to display information directly from the Ramp APIs. Superceded by ramp-lookup. |
ramp-lookup | Application for looking up information about Ramp content, using the local database. |
ramp-refresh | Node-based Application originally intended to download content from the Ramp API and storing it in a local database. |
The relevant packages (in the packages directory) are:
Package | Description |
---|---|
eslint-config | ESLint configuration files, including eslint-config-next and eslint-config-prettier , which can be used by the applications and packages in this monorepo. |
jest-presets | Jest configuration files, which can be used by the applications and packages in this monorepo. |
ramp-api | Server side logic to call the Ramp APIs, which can be used to download content from Ramp. |
ramp-db | Contains a Prisma schema for the local database, which contains tables for content downloaded with the Ramp APIs, along with a generated Prisma client for that schema. |
shared-utils | Shared utility functions that can be used by the applications and packages in this monorepo. |
typescript-config | TypeScript configuration files, which can be used by the applications and packages in this monorepo. |
The following global dependencies are required to work with this repository, and must be installed using the instructions on each of their respective websites:
-
Node.js (use the latest LTS version). This is the server side runtime used to execute applications. Includes
npm
, a package manager for Node.js based applications, but we will not be using it (except to installpnpm
as described next). -
pnpm (use the latest version). This is the package manager we will be using to install dependencies for the applications and packages in this monorepo. It is a drop-in replacement for
npm
, but has much better performance and disk space usage, because it caches a single copy of each package in a global location, and then symlinks that copy into each application or package that requires it. You can usenpm
to installpnpm
, as described on the installation page. -
Turborepo (use the latest version). This is the monorepo management tool that we will be using to manage the applications and packages in this repository. It is installed as a global package using
pnpm
.
In the parent directory into which you want to clone the repository, run:
git clone https://github.com/craigmcc/apache-turborepo.git
All of the subsequent commands should be run from within the
apache-turborepo
directory.
Next, install the dependencies for the monorepo by running:
cd apache-turborepo ## If you are not already in the repository directory
pnpm install
There is a step needed before the global build, to generate the Prisma client and types that will be used to access the local database. This is done by running:
cd packages/ramp-db
pnpm run db-ramp:generate
cd ../..
After that, you can build the entire monorepo by running (from the root of the repository):
turbo run build
To create the local database, you must first set up a .env
file, in the
package directory packages/ramp-db/
. This file should contain a single
variable defining the location of the local database file, for example:
DATABASE_URL="file:/Users/craigmcc/sqlite/ramp-db.db"
You must create the directory where the database file will be stored, if it does not exist, but the database file itself will be created automatically when you run the next command.
Now, you can create the local database, and configure its tables, by running:
cd packages/ramp-db
turbo run db-ramp:migrate
This will create the database file (if it does not exist yet), apply the initial
database schema to it, followed by any migrations that have been defined in the
packages/prisma/migrations
directory. The end result will be that the database
is configured exactly as defined by the current Prisma schema, as of the time you
most recently pulled the repository from Github.
Next, we are going to use the ramp-refresh
application to download information
from Ramp, and populate the local database with that content. Before you can do this,
however, you must first configure a .env
file in the apps/ramp-refresh/
directory,
with the following environment variables:
Variable Name | Description |
---|---|
DATABASE_URL | The location of the local database file, same as what was configured for ramp-db above. |
RAMP_PROD_API_BASE_URL | The base URL for the Ramp production API, e.g. https://api.ramp.com . |
RAMP_PROD_API_CLIENT_ID | The client ID for your Ramp production API application, as configured in the Ramp developer portal. |
RAMP_PROD_API_CLIENT_SECRET | The client secret for your Ramp production API application, as configured in the Ramp developer portal. |
RAMP_PROD_API_SCOPE | Space-separated list of scopes for the Ramp production API (see below). |
The list of scopes you will need for the Ramp API calls will depend on which tables we are downloading. The following scopes are required for the tables that we currently download:
accounting:read cards:read departments:read limits:read spend_programs:read transactions:read users:read
Now, you can run the ramp-refresh
application to download the content from Ramp and
load it into the local database. This is done by running:
cd apps/ramp-refresh
turbo run build
pnpm run start
cd ../..
This is a Node-based application that outputs its progress to the terminal window, and then exits when it is finished. It is suitable to be run periodically to update the local database with the latest content from Ramp, and it can be run as often as you like, or even run it periodically with a cron job.
Now, if you use any of the various SQLite database browsers, you will be able to
see that all of the tables have been populated with the current content from Ramp,
as of the moment you ran this application. It can be run again at any time
without problems, because it uses Prisma's upsert
functionality to insert new
rows or update existing rows, based on the unique primary key for each table.
Next, set up a .env
file in the apps/ramp-lookup/
directory, with only the
DATABASE_URL variable, which should point to the same local database file. Now,
you can run the ramp-lookup
application to view the content of the local database.
cd apps/ramp-lookup
turbo run build
pnpm run dev
Then point your browser at http://localhost:3000
. When you want to stop the
app, you can cancel it with Ctrl-C in the terminal window where it is running
and return to the repo's root directory.
Running in development mode will automatically reload the application when you make changes to the source code, so you can easily make changes and see the results.
You will periodically want to pull the latest code changes from the Git repository. To do so, run the following commands from the root of the repository:
git pull
If there have been any changes, you will typically need to regenerate the Prisma client, rebuild the entire monorepo, and then run the migration command to update the local database:
cd packages/ramp-db
turbo run db-ramp:generate
cd ../..
turbo run build
cd packages/ramp-db
turbo run db-ramp:migrate
Periodically, you will also want to update the local database content with the latest information from Ramp. This will be something you will want to do if there have been code changes (such as supporting for new tables or updated schema definitions):
cd apps/ramp-refresh
turbo run build
pnpm run start
As before, you can run the ramp-lookup
application to view the updated content in the local database:
cd apps/ramp-lookup
turbo run build
pnpm run dev
If you look at the package.json
files in the various applications and packages,
you will see two interesting types of dependency declarations:
workspace:*
- This means that the dependency is a local package in the monorepo, and it will be resolved to the latest version of that package in the monorepo. This is used for packages that are part of the same monorepo, such as@repo/ramp-db
.catalog:foo
- This means that the actual version of the dependency is stored in thepnpm-workspace.yaml
file in the root of the monorepo. Declaring dependencies this way allows us to ensure that the same version of the same dependency is used across the entire monorepo.
We are using the Catalogs feature of pnpm
to manage the versions of our dependencies
globally, so that we can ensure that all applications and packages in the monorepo
use the same version of a dependency.
You can run the following command from the root of the monorepo to check the source code in each package for correct styling, as defined by the ESLint configuration:
turbo run lint
This will run the lint
script in each package and application that has one defined.
There are woefully few at the moment, but the packages and applications have been configured to use Jest for unit testing. You can run the tests in each package by navigating to it's root directory, and running one of the following commands:
pnpm run test
- Runs the tests in the package, and watches for changes to the source code of that package or application, and re-runs the tests then.pnpm run test:ci
- Runs the tests in the package, but does not watch for changes to the source code. This is useful for running tests in a continuous integration environment, such as GitHub Actions.
Yes, defined in the file .github/workflows/ci.yml
. This workflow is triggered
when a push happens to the main branch, and performs the following steps:
- Check out the code from the repository.
- Set up
pnpm
. - Set up
NodeJS
. - Install the dependencies for the monorepo.
- Generate the Prisma client and types for the local database.
- Build the entire monorepo.
- Runs the tests in each package and application via
pnpm run test:ci
.
Results of these workflow runs can be seen in the "Actions" tab of the repository on GitHub.
To avoid causing inadvertent CI failures, it is recommended that you run the following commands (from the root of the monorepo) before pushing any changes:
turbo run lint
turbo run build
turbo run test:ci
While it is configured (.github/dependabot.yml
), GitHub does not currently
seem to support Dependabot for monorepos. This means that Dependabot will not
create pull requests to update the dependencies in the monorepo, and you will
need to manually update the dependencies in the pnpm-workspace.yaml
file
before rebuilding everything.
TODO.