Note
Harper open source core is still under active development.
The source code in this repository was extracted directly from our old, closed-source codebase.
Stay tuned to this repo and our public channels (such as our Discord community) for updates as we continue to develop the future of open source Harper.
Contributors are encouraged to communicate with maintainers in issues or other channels (such as our community Discord) before submitting changes.
Install dependencies using npm install
Build the project using npm run build or npm run build:watch to automatically rebuild on file changes.
Run integration tests using npm run test:integration. Make sure to read the integration test instructions for setup requirements (particularly the loopback address configuration).
Run unit tests using npm run test:unit <unit-test-file> or npm run test:unit:all, but make sure to build the project first since unit tests depend on the built source files.
Unit tests currently use Mocha as the test runner, but since they are implemented in TypeScript and are sometimes executing TypeScript source code, it also uses TSX for compilation and execution. The npm script
test:unitsets the appropriate env vars and mocha configuration file. Make sure that theTSX_TSCONFIG_PATHenvironment variable points to the correcttsconfig.jsonfile for the unit tests (i.e../unitTests/tsconfig.json) and not the root-leveltsconfig.json.
We currently use prettier and eslint to enforce code formatting and
linting, respectively. While we do enforce conformity to prettier's ruleset in CI, we're taking an incremental approach
with eslint. Rules that can be globally enforced are enabled in the eslint.required.config.mjs file, while the
aspirational rules are in eslint.config.mjs. This is because when editing or linting new code locally, we want to
adhere to the full ruleset in eslint.config.mjs. But in CI we only want to enforce those rules enabled in
eslint.required.config.mjs. We will enable additional rules in eslint.required.config.mjs over time until there is
one ruleset that is enforced everywhere. PRs that allow enabling additional eslint rules are welcome!
We use Renovate to automatically update dependencies on a regular schedule (with a cooldown period to help guard against supply chain attacks).
This is configured in the renovate.json file in the project root. Renovate will open pull requests when it detects available updates and
Harper staff will review these and merge them on a case-by-case basis. But contributors should feel free to comment on any pull requests
they have feedback on. But in general, manually opening PRs to update dependencies is not necessary thanks to this automation.
Most of the content within this repo is source files. The exceptions are static and test directories, and various configuration files (such as eslint.config.mjs, prettier.config.mjs, and tsconfig.json).
This section is only relevant to repository maintainers responsible for the temporary synchronization of the old, internal repository and this one.
These are the steps @Ethan-Arrowood has been following to synchronize the repositories; particularly bringing commits forward from the old repo to this new one, but the steps could reasonably be used in the reverse direction too.
This procedure assume the old, internal repo is set as the
oldgit remotegit remote add old <internal repo URL> # Only fetch `main` branch git config remote.old.fetch '+refs/heads/main:refs/remotes/old/main'
- Make sure local
mainbranch is checked out and cleangit checkout main && git status. - Copy the latest previously-synced commit hash from this file.
- Run the sync-commits helper script:
dev/sync-commits.js <previously-synced-commit-hash> - For each commit the script lists, run the
git cherry-pick ...command it suggests.- NB: Some of these may have
-m 1params to handle merge commits correctly.
- NB: Some of these may have
- If either cherry-pick command results in a non-zero exit code that means there is a merge conflict.
- If the conflict is a content, resolve it manually and
git addthe file- Example:
CONFLICT (content): Merge conflict in package.json
- Example:
- Else if the conflict is a modify/delete then likely
git rmthe file- Example:
CONFLICT (modify/delete): unitTests/bin/copyDB-test.js deleted in HEAD and modified in f75d9170b
- Example:
- Then check
git status, if there is nothing you cangit cherry-pick --skip- Note: in this circumstance, running
git cherry-pick --continueresults in a non-zero exit code with the messageThe previous cherry-pick is now empty, possibly due to conflict resolution.Maybe we use this to then run--skip? Or maybe there is a way to parse the output of previousgit statusstep?
- Note: in this circumstance, running
- If the conflict is a content, resolve it manually and
- After all commits have been picked, manually check that everything brought over was supposed to be. Look out for any source code we do not want open-sourced or things like unit tests which we are actively migrating separately (and will eventually include as part of the synchronization process)
- The GitHub PR UI is useful for this step; but make sure to leave the PR as a draft until all synchronization steps are complete
- Once everything looks good, run
npm run format:writeto ensure formatting is correct - Commit the formatting changes
- Add the formatting changes commit from the previous step to the
.git-blame-ignore-revsfile under the# Formatting Changessection - Record the last commit that was cherry-picked from
old/mainand record it below in order to make the next synchronization easier. Make sure to record the commit hash fromold/mainand not the new hash - Commit the changes to
CONTRIBUTING.mdto mark the synchronization complete - Push all changes and open the PR for review
- Merge using a Merge Commit so that all relative history is retained and things like the formatting change hash stays the same as recorded.
f7d75323a11e9f65b6a838e4afe531eb3f59b593
Harper has a Code of Conduct that all contributors are expected to follow.