Thank you for considering contributing to the NEAR Indexer for Explorer!
We welcome all external contributions. This document outlines the process of contributing to NEAR Indexer for Explorer.
For contributing to other repositories, see CONTRIBUTING.md
in the corresponding repository.
For non-technical contributions, such as e.g. content or events, see this document.
All the contributions to NEAR Indexer for Explorer happen via Pull Requests. To create a Pull Request, fork NEAR Indexer for Explorer repository on GitHub, create a new branch, do the work there, and then send the PR via GitHub interface.
The PRs should always be against the master
branch.
The exact process depends on the particular contribution you are making.
If you see an obvious typo, or an obvious bug that can be fixed with a small change, in the code or documentation, feel free to submit the pull request that fixes it without opening an issue.
Once your change is ready, prepare the PR. The PR can contain any number of commits, but when it is merged, they will all get squashed. The commit names and descriptions can be arbitrary, but the name and the description of the PR must follow the following template:
<type>: <name>
<description>
Test plan
---------
<test plan>
Where type
is fix
for fixes, feat
for features, refactor
for changes that primarily reorganize code, doc
for changes that primarily change documentation or comments, and test
for changes that primarily introduce new tests. The type is case sensitive.
The test plan
should describe in detail what tests are presented, and what cases they cover.
- We have a CI process configured to run all the sanity tests on each PR. If the CI fails on your PR, you need to fix it before it will be reviewed.
- Once the CI passes, you should expect the first feedback to appear within 48 hours. The reviewers will first review your tests, and make sure that they can convince themselves the test coverage is adequate before they even look into the change, so make sure you tested all the corner cases.
- Once you address all the comments, and your PR is accepted, we will take care of merging it.
If you want to propose an idea or a feature and work on it, create a new issue in the near-indexer-for-Explorer
repository.
You should expect someone to comment on the issue within 48 hours after it is created.
We enforce formatting with rustfmt, so your code should be formatted with cargo fmt
and checked with cargo clippy
to pass CI. Additionally, we extend those default rules with some extras.
We use the following order to group our imports (use statements):
- standard Rust library imports (e.g.
std::sync::Arc
) - external crates (e.g.
tokio::time
) - near-* crates (e.g.
near_lake_framework::near_indexer_primitives::types
) - local crate modules (e.g.
crate::db
) - local modules (e.g.
self::access_keys
) mod
statements
Separate each group with an empty line and maintain alphabetical order inside of each group (it is done automatically by rustfmt).
Here is an artificial example:
use std::path::PathBuf;
use std::sync::Arc;
use tokio::time;
use near_indexer::near_primitives;
pub use crate::db::AccessKey;
use self::db;
mod access_keys;
mod utils;
Try to avoid wildcard imports on a module level as they are hard to reason about. Note, it is fine to use them in a limited scope, e.g. inside a function, macro, etc.
To improve readability, try to avoid importing individual structs, functions, etc unless they are nonambiguous.
We prefer this:
use near_indexer::near_primitives;
fn my_func() {
let my_account = near_primitives::types::Account::from("test.near");
}
over:
use near_lake_framework::near_indexer_primitives::types::Account;
fn my_func() {
let my_account = Account::from("test.near");
}
The rationale behind this is that there are plenty of different Account
types in various contexts (e.g. DB schema, NEAR account, local crate struct).
Use specific versioning when specifying dependencies. It helps to mitigate potential security vulnerabilities and reason through code better.
- Check the crate's dependencies to ensure that they are also reputable and secure
- Check the crate's source repository for the latest issues that are related to security
- Consider using crates that have been around for a while and have a large active user base, as this can indicate that they have stood the test of time and are likely to be stable and secure.
We use the following order to group our dependencies in Cargo.toml:
- all external dependencies (e.g.
actix = "0.13.0"
) - all NEAR dependencies (e.g.
near-primitives = "0.14.0"
)
Separate the group of dependencies with an empty line and maintain alphabetical order inside of each group. Additionally, leave one empty line at the end of the file.
We created a list of things that should be surely fixed before the review. It will save your time and the time of the reviewer. Here it is:
- Automatic checks
cargo fmt
cargo clippy
- Code structure
- Is the code self-explanatory? Can you rewrite it to be so? If not, can you add some comments to make the life of the future you easier? Consider using links to other materials if it's suitable
- Take care of function parameter types and return values. Do something meaningful if you know Rust; otherwise, simply pass parameters by reference (&)
- Use as narrow scope as you can. At least change
pub
topub(crate)
- Imports & Dependencies
- Imports should be frugal. Read about it above
- Use relative import (
super
) if you use the same module - Check imports ordering
- Check dependency ordering
- Types
- Use
str
instead ofString
if it's possible - Use wrapper type instead of a raw one. E.g.
AccountId
instead ofstr
,Duration
instead ofu64
- Use
- Wording
- Get rid of short name versions, we do not pay for symbols.
account_id
is better thanacc
- Spend time on the naming of variables and functions. It does matter. Look around, the codebase should help you
- Spend time on the wording in logging. Does it explain what is going on? Does it help to solve the issue?
- Use Grammarly for docstrings
- Get rid of short name versions, we do not pay for symbols.
- "I just learn Rust and I do weird things"
x.to_string().as_str()
->&x.to_string()
for x in items.iter()
->for x in &items
- Use
{:?}
if you need to log the value and{}
does not work - Do not use
return
if you can, it's Rust, the last statement is the result for the function
- Do not forget to re-check everything again before sending the code
(...to be continued)
nearcore
uses nightly Rust features, so you will need nightly rust installed. See this document for details. NEAR Indexer for Explorer follows rust-toolchain
specified by nearcore
.
Majority of NEAR developers use CLion with Rust plugin as their primary IDE.
We also had success with VSCode with rust-analyzer, see the steps for installation here.
Some of us use VIM with rust.vim and rusty-tags. It has fewer features than CLion or VSCode, but overall provides a usable setting.
Refer to this document for details on setting up your environment.
Steps to make a new shiny release:
- Do something great and merge it to master
- Read through all the commits after the last release
- Pick the new version, update
CHANGELOG.md
with all the noticeable changes - Update the version in
Cargo.toml
and push the changes - If the team approves your PR, go to Releases tab and "Draft a new release". You need to create tag as well (available from UI)