feat: release workflow (#2677)

This commit is contained in:
Bjerg
2023-05-19 19:48:23 +02:00
committed by GitHub
parent 2837fb6b9a
commit 8e89360774
15 changed files with 462 additions and 63 deletions

View File

@ -2,4 +2,5 @@
/book
/assets
/.github
Dockerfile
/data
*.tar.gz

244
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,244 @@
# This workflow is borrowed from Lighthouse: https://github.com/sigp/lighthouse/blob/693886b94176faa4cb450f024696cb69cda2fe58/.github/workflows/release.yml
name: release
on:
push:
tags:
- v*
env:
REPO_NAME: ${{ github.repository_owner }}/reth
IMAGE_NAME: ${{ github.repository_owner }}/reth
jobs:
extract-version:
runs-on: ubuntu-latest
steps:
- name: Extract version
run: echo "VERSION=$(echo ${GITHUB_REF#refs/tags/})" >> $GITHUB_OUTPUT
id: extract_version
outputs:
VERSION: ${{ steps.extract_version.outputs.VERSION }}
build:
name: build release
strategy:
matrix:
arch: [aarch64-unknown-linux-gnu,
x86_64-unknown-linux-gnu,
x86_64-apple-darwin,
x86_64-windows]
include:
- arch: aarch64-unknown-linux-gnu
platform: ubuntu-latest
profile: maxperf
- arch: x86_64-unknown-linux-gnu
platform: ubuntu-latest
profile: maxperf
- arch: x86_64-apple-darwin
platform: macos-latest
profile: maxperf
- arch: x86_64-windows
platform: windows-2019
profile: maxperf
runs-on: ${{ matrix.platform }}
needs: extract-version
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Get latest version of stable Rust
run: rustup update stable
# ==============================
# Windows dependencies
# ==============================
- uses: KyleMayes/install-llvm-action@v1
if: startsWith(matrix.arch, 'x86_64-windows')
with:
version: "13.0"
directory: ${{ runner.temp }}/llvm
- name: Set LIBCLANG_PATH
if: startsWith(matrix.arch, 'x86_64-windows')
run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV
# ==============================
# Builds
# ==============================
- name: Build reth for aarch64-unknown-linux-gnu
if: matrix.arch == 'aarch64-unknown-linux-gnu'
run: |
cargo install cross
env CROSS_PROFILE=${{ matrix.profile }} make build-aarch64
- name: Build reth for x86_64-unknown-linux-gnu
if: matrix.arch == 'x86_64-unknown-linux-gnu'
run: |
cargo install cross
env CROSS_PROFILE=${{ matrix.profile }} make build-x86_64
- name: Move cross-compiled binary
if: startsWith(matrix.arch, 'aarch64')
run: mv target/aarch64-unknown-linux-gnu/${{ matrix.profile }}/reth ~/.cargo/bin/reth
- name: Move cross-compiled binary
if: startsWith(matrix.arch, 'x86_64-unknown-linux-gnu')
run: mv target/x86_64-unknown-linux-gnu/${{ matrix.profile }}/reth ~/.cargo/bin/reth
- name: Build reth for x86_64-apple-darwin modern
if: matrix.arch == 'x86_64-apple-darwin'
run: cargo install --path reth --force --locked --profile ${{ matrix.profile }}
- name: Build reth for Windows modern
if: matrix.arch == 'x86_64-windows'
# NOTE: profile set to release (see above)
run: cargo install --path reth --force --locked --profile release
- name: Configure GPG and create artifacts
if: startsWith(matrix.arch, 'x86_64-windows') != true
env:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: |
export GPG_TTY=$(tty)
echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import
mkdir artifacts
mv ~/.cargo/bin/reth ./artifacts
cd artifacts
tar -czf reth-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.arch }}.tar.gz reth
echo "$GPG_PASSPHRASE" | gpg --passphrase-fd 0 --pinentry-mode loopback --batch -ab reth-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.arch }}.tar.gz
mv *tar.gz* ..
- name: Configure GPG and create artifacts Windows
if: startsWith(matrix.arch, 'x86_64-windows')
env:
GPG_SIGNING_KEY: ${{ secrets.GPG_SIGNING_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: |
echo $env:GPG_SIGNING_KEY | base64 --decode | gpg --batch --import
mkdir artifacts
move $env:USERPROFILE/.cargo/bin/reth.exe ./artifacts
cd artifacts
tar -czf reth-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.arch }}.tar.gz reth.exe
gpg --passphrase "$env:GPG_PASSPHRASE" --batch --pinentry-mode loopback -ab reth-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.arch }}.tar.gz
move *tar.gz* ..
# =======================================================================
# Upload artifacts
# This is required to share artifacts between different jobs
# =======================================================================
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: reth-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.arch }}.tar.gz
path: reth-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.arch }}.tar.gz
- name: Upload signature
uses: actions/upload-artifact@v3
with:
name: reth-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.arch }}.tar.gz.asc
path: reth-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.arch }}.tar.gz.asc
draft-release:
name: Draft Release
needs: [build, extract-version]
runs-on: ubuntu-latest
env:
VERSION: ${{ needs.extract-version.outputs.VERSION }}
steps:
# This is necessary for generating the changelog. It has to come before "Download Artifacts" or else it deletes the artifacts.
- name: Checkout sources
uses: actions/checkout@v3
with:
fetch-depth: 0
# ==============================
# Download artifacts
# ==============================
- name: Download artifacts
uses: actions/download-artifact@v3
# ==============================
# Create release draft
# ==============================
- name: Generate Full Changelog
id: changelog
run: |
echo "CHANGELOG<<EOF" >> $GITHUB_OUTPUT
echo "$(git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 ${{ env.VERSION }}^)..${{ env.VERSION }})" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create Release Draft
env:
GITHUB_USER: ${{ github.repository_owner }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# The formatting here is borrowed from Lighthouse (which is borrowed from OpenEthereum): https://github.com/openethereum/openethereum/blob/main/.github/workflows/build.yml
run: |
body=$(cat <<- "ENDBODY"
<Release Name>
## Testing Checklist (DELETE ME)
- [ ] Run on testnet for 1-3 days.
- [ ] Resync a mainnet node.
- [ ] Ensure all CI checks pass.
## Release Checklist (DELETE ME)
- [ ] Ensure all crates have had their versions bumped.
- [ ] Write the summary.
- [ ] Fill out the update priority.
- [ ] Ensure all binaries have been added.
- [ ] Prepare release posts (Twitter, ...).
## Summary
Add a summary, including:
- Critical bug fixes
- New features
- Any breaking changes (and what to expect)
## Update Priority
This table provides priorities for which classes of users should update particular components.
| User Class | Priority |
|----------------------|-----------------|
| Payload Builders | <TODO> |
| Non-Payload Builders | <TODO> |
*See [Update
Priorities](https://paradigmxyz.github.io/reth/installation-priorities.html)
more information about this table.*
## All Changes
${{ steps.changelog.outputs.CHANGELOG }}
## Binaries
[See pre-built binaries documentation.](https://https://paradigmxyz.github.io/reth/installation/binaries.html)
The binaries are signed with the PGP key: `A3AE 097C 8909 3A12 4049 DF1F 5391 A3C4 1005 30B4`
| System | Architecture | Binary | PGP Signature |
|:---:|:---:|:---:|:---|
| <img src="https://simpleicons.org/icons/apple.svg" style="width: 32px;"/> | x86_64 | [reth-${{ env.VERSION }}-x86_64-apple-darwin.tar.gz](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/reth-${{ env.VERSION }}-x86_64-apple-darwin.tar.gz) | [PGP Signature](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/reth-${{ env.VERSION }}-x86_64-apple-darwin.tar.gz.asc) |
| <img src="https://simpleicons.org/icons/linux.svg" style="width: 32px;"/> | x86_64 | [reth-${{ env.VERSION }}-x86_64-unknown-linux-gnu.tar.gz](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/reth-${{ env.VERSION }}-x86_64-unknown-linux-gnu.tar.gz) | [PGP Signature](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/reth-${{ env.VERSION }}-x86_64-unknown-linux-gnu.tar.gz.asc) |
| <img src="https://simpleicons.org/icons/raspberrypi.svg" style="width: 32px;"/> | aarch64 | [reth-${{ env.VERSION }}-aarch64-unknown-linux-gnu.tar.gz](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/reth-${{ env.VERSION }}-aarch64-unknown-linux-gnu.tar.gz) | [PGP Signature](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/reth-${{ env.VERSION }}-aarch64-unknown-linux-gnu.tar.gz.asc) |
| <img src="https://simpleicons.org/icons/windows.svg" style="width: 32px;"/> | x86_64 | [reth-${{ env.VERSION }}-x86_64-windows.tar.gz](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/reth-${{ env.VERSION }}-x86_64-windows.tar.gz) | [PGP Signature](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/reth-${{ env.VERSION }}-x86_64-windows.tar.gz.asc) |
| | | | |
| **System** | **Option** | - | **Resource** |
| <img src="https://simpleicons.org/icons/docker.svg" style="width: 32px;"/> | Docker | [${{ env.VERSION }}](https://hub.docker.com/r/${{ env.IMAGE_NAME }}/tags?page=1&ordering=last_updated&name=${{ env.VERSION }}) | [${{ env.IMAGE_NAME }}](https://hub.docker.com/r/${{ env.IMAGE_NAME }}) |
ENDBODY
)
assets=()
for asset in ./reth-*.tar.gz*; do
assets+=("-a" "$asset/$asset")
done
tag_name="${{ env.VERSION }}"
echo "$body" | hub release create --draft "${assets[@]}" -F "-" "$tag_name"

24
Cargo.lock generated
View File

@ -501,17 +501,6 @@ dependencies = [
"serde",
]
[[package]]
name = "built"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96f9cdd34d6eb553f9ea20e5bf84abb7b13c729f113fc1d8e49dc00ad9fa8738"
dependencies = [
"cargo-lock",
"chrono",
"semver 1.0.17",
]
[[package]]
name = "bumpalo"
version = "3.12.0"
@ -554,18 +543,6 @@ dependencies = [
"serde",
]
[[package]]
name = "cargo-lock"
version = "8.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996"
dependencies = [
"semver 1.0.17",
"serde",
"toml 0.5.11",
"url",
]
[[package]]
name = "cargo-platform"
version = "0.1.2"
@ -4556,7 +4533,6 @@ name = "reth"
version = "0.1.0"
dependencies = [
"backon",
"built",
"clap 4.1.8",
"comfy-table",
"confy",

5
Cross.toml Normal file
View File

@ -0,0 +1,5 @@
[build]
pre-build = [
# rust-bindgen dependencies: llvm-dev libclang-dev (>= 5.0) clang (>= 5.0)
"apt-get update && apt-get install --assume-yes --no-install-recommends llvm-dev libclang-6.0-dev clang-6.0"
]

View File

@ -10,7 +10,7 @@ FROM chef AS builder
COPY --from=planner /app/recipe.json recipe.json
# Set the build profile to be release
ARG BUILD_PROFILE=release
ARG BUILD_PROFILE=maxperf
ENV BUILD_PROFILE $BUILD_PROFILE
# Install system dependencies

81
Makefile Normal file
View File

@ -0,0 +1,81 @@
# Heavily inspired by Lighthouse: https://github.com/sigp/lighthouse/blob/693886b94176faa4cb450f024696cb69cda2fe58/Makefile
GIT_TAG := $(shell git describe --tags --candidates 1)
BIN_DIR = "bin"
X86_64_TAG = "x86_64-unknown-linux-gnu"
BUILD_PATH_X86_64 = "target/$(X86_64_TAG)/release"
AARCH64_TAG = "aarch64-unknown-linux-gnu"
BUILD_PATH_AARCH64 = "target/$(AARCH64_TAG)/release"
# List of features to use when building natively. Can be overriden via the environment.
# No jemalloc on Windows
ifeq ($(OS),Windows_NT)
FEATURES?=
else
FEATURES?=jemalloc
endif
# List of features to use when cross-compiling. Can be overridden via the environment.
CROSS_FEATURES ?= jemalloc
# Cargo profile for Cross builds. Default is for local builds, CI uses an override.
CROSS_PROFILE ?= release
# Cargo profile for regular builds.
PROFILE ?= release
# Extra flags for Cargo
CARGO_INSTALL_EXTRA_FLAGS ?=
# Builds the reth binary in release (optimized).
#
# Binaries will most likely be found in `./target/release`
install:
cargo install --path reth --force --locked \
--features "$(FEATURES)" \
--profile "$(PROFILE)" \
$(CARGO_INSTALL_EXTRA_FLAGS)
# The following commands use `cross` to build a cross-compile.
#
# These commands require that:
#
# - `cross` is installed (`cargo install cross`).
# - Docker is running.
# - The current user is in the `docker` group.
#
# The resulting binaries will be created in the `target/` directory.
#
# Note: The additional rustc compiler flags are for intrinsics needed by MDBX.
# See: https://github.com/cross-rs/cross/wiki/FAQ#undefined-reference-with-build-std
build-x86_64 build-aarch64: export RUSTFLAGS=-C link-arg=-lgcc -Clink-arg=-static-libgcc
build-x86_64:
cross build --bin reth --target x86_64-unknown-linux-gnu --features "$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)"
build-aarch64:
cross build --bin reth --target aarch64-unknown-linux-gnu --features "$(CROSS_FEATURES)" --profile "$(CROSS_PROFILE)"
# Create a `.tar.gz` containing a binary for a specific target.
define tarball_release_binary
cp $(1)/reth $(BIN_DIR)/reth
cd $(BIN_DIR) && \
tar -czf reth-$(GIT_TAG)-$(2)$(3).tar.gz reth && \
rm reth
endef
# Create a series of `.tar.gz` files in the BIN_DIR directory, each containing
# a `reth` binary for a different target.
#
# The current git tag will be used as the version in the output file names. You
# will likely need to use `git tag` and create a semver tag (e.g., `v0.2.3`).
build-release-tarballs:
[ -d $(BIN_DIR) ] || mkdir -p $(BIN_DIR)
$(MAKE) build-x86_64
$(call tarball_release_binary,$(BUILD_PATH_X86_64),$(X86_64_TAG),"")
$(MAKE) build-aarch64
$(call tarball_release_binary,$(BUILD_PATH_AARCH64),$(AARCH64_TAG),"")
# Performs a `cargo` clean
clean:
cargo clean

View File

@ -7,10 +7,6 @@ repository = "https://github.com/paradigmxyz/reth"
readme = "README.md"
build = "build.rs"
# Add jemalloc for extra perf on Linux systems.
[target.'cfg(all(not(windows), not(target_env = "musl")))'.dependencies]
jemallocator = "0.5.0"
[dependencies]
# reth
reth-primitives = { path = "../../crates/primitives", features = ["arbitrary"] }
@ -39,7 +35,7 @@ reth-net-nat = { path = "../../crates/net/nat" }
reth-payload-builder = { path = "../../crates/payload/builder" }
reth-basic-payload-builder = { path = "../../crates/payload/basic" }
reth-discv4 = { path = "../../crates/net/discv4" }
built = { version = "0.6", features = ["chrono", "semver"] }
jemallocator = { version = "0.5.0", optional = true }
# crypto
secp256k1 = { version = "0.27.0", features = [
@ -93,6 +89,7 @@ thiserror = "1.0"
pretty_assertions = "1.3.0"
[features]
jemalloc = ["dep:jemallocator"]
only-info-logs = ["tracing/release_max_level_info"]
[build-dependencies]

View File

@ -23,5 +23,6 @@ pub mod test_eth_chain;
pub mod test_vectors;
pub mod utils;
pub mod version;
use built as _;
#[cfg(feature = "jemalloc")]
use jemallocator as _;

View File

@ -1,5 +1,5 @@
// We use jemalloc for performance reasons
#[cfg(all(not(windows), not(target_env = "musl")))]
#[cfg(feature = "jemalloc")]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

View File

@ -5,6 +5,7 @@
1. [Pre-Built Binaries](./installation/binaries.md)
1. [Docker](./installation/docker.md)
1. [Build from Source](./installation/source.md)
1. [Update Priorities](./installation/priorities.md)
1. [Run a Node](./run/run-a-node.md)
1. [Mainnet or official Testnets](./run/mainnet.md)
1. [Local Testnet](./run/local_testnet.md)

View File

@ -0,0 +1,18 @@
# Update Priorities
When publishing releases, reth will include an "Update Priority" section in the release notes, in the same manner Lighthouse does.
The "Update Priority" section will include a table which may appear like so:
| User Class | Priority |
|----------------------|-----------------|
| Payload Builders | Medium Priority |
| Non-Payload Builders | Low Priority |
To understand this table, the following terms are important:
- *Payload builders* are those who use reth to build and validate payloads.
- *Non-payload builders* are those who run reth for other purposes (e.g., data analysis, RPC or applications).
- *High priority* updates should be completed as soon as possible (e.g., hours or days).
- *Medium priority* updates should be completed at the next convenience (e.g., days or a week).
- *Low priority* updates should be completed in the next routine update cycle (e.g., two weeks).

View File

@ -8,4 +8,5 @@ This directory contains documentation for contributors.
### Meta
- [Releasing](./release.md)
- [Workflow](./workflow.md): The lifecycle of PRs
- [Releases](./release.md): How reth is released and when (for maintainers)

View File

@ -1,35 +1,47 @@
## Releasing
## Releases
This document outlines how to cut a new release.
### Release cadence
### Checklist
**reth does not currently have a regular release cadence while it is still experimental software**.
### For maintainers
This section outlines how to cut a new release.
It is assumed that the commit that is being considered for release has been marked as stable, i.e. that there is an expectation of no major bugs.
- [ ] Ensure *all* tests and lints pass
- [ ] Changelog
- [ ] Ensure the changelog is up to date by going over https://github.com/paradigmxyz/reth/labels/M-changelog
- [ ] Move the "Unreleased" section in [CHANGELOG.md](./CHANGELOG.md) into a header with the new version, and add a link at the bottom of the changelog to compare the new version to HEAD.
- [ ] Version bump
- [ ] Update the version in `Cargo.toml`
- [ ] Commit the changes
- The message format should be `release: x.y.z`, substituting `x.y.z` for the semver.
- [ ] Tag the new commit with `x.y.z`
- [ ] Push the changes, including the tag
#### Release PR
After pushing the tag, CI will start building the release, bundling it, and publishing it to package managers and crates.io. (TBD)
- [ ] Create a new branch (e.g. `release/vx.y.z`) and open a pull request for it
- [ ] Ensure *all* tests and lints pass for the chosen commit
- [ ] Version bump
- [ ] Update the version in *all* `Cargo.toml`'s
- [ ] Commit the changes
- The message format should be `release: vx.y.z`, substituting `x.y.z` for the semver.
- [ ] The PR should be reviewed to see if anything was missed
- [ ] Once reviewed, merge the PR
#### Releasing
- [ ] Tag the new commit on main with `vx.y.z` (`git tag vx.y.z SHA`)
- [ ] Push the tag (`git push origin vx.y.z`)[^1]
- [ ] Run the release commit on testing infrastructure for 1-3 days to check for inconsistencies and bugs
- This testing infrastructure is going to sync and keep up with a live testnet, and includes monitoring of bandwidth, CPU, disk space etc.
> **Note**
> This is a work in progress. There are still some unknowns:
>
> - Should we require that the commit is signed?
> - Should we publish crates to crates.io? Should each crate use the same version?
>
> Additionally, a workflow needs to be added that:
>
> - Builds the release (cross-platform)
> - Runs *all* tests once more, even the long ones
> - Bundles the release with any aux files (license, config, ...)
> - Publishes the release to GitHub, brew, Dockerhub, Arch, ...
> - Publishes crates to crates.io
> - Creates a GitHub release, copying over the relevant section of the changelog
>
> The `v` prefix for the tag is important! If it is missing, the release workflow **will not run**.
When the tag is pushed, the artifacts are built automatically and a draft release is added to the repository. This draft release includes a template that must be filled out, including:
- A summary of the release (highlights etc.)
- The update priority (see below)
- An auto-generated changelog
The release artifacts are automatically added to the draft release. Once ready, simply publish the release.
#### Release summaries
The release summary should include general notes on what the release contains that is important to operators. These changes can be found using the https://github.com/paradigmxyz/reth/labels/M-changelog label.
[^1]: It is possible to use `git push --tags`, but this is discouraged since it can be very difficult to get rid of bad tags.

View File

@ -18,7 +18,7 @@ The CI runs a couple of workflows:
- **[deny]**: Runs `cargo deny` to check for license conflicts and security advisories in our dependencies
- **[sanity]**: Runs a couple of sanity checks on the code every night, such as checking for unused dependencies
- **[project]**: [GitHub Projects][gh-projects] automation.
- **[release]**: Runs the release workflow
[ci]: https://github.com/paradigmxyz/reth/blob/main/.github/workflows/ci.yml
[unit]: https://github.com/paradigmxyz/reth/blob/main/.github/workflows/unit.yml
@ -28,5 +28,5 @@ The CI runs a couple of workflows:
[book]: https://github.com/paradigmxyz/reth/blob/main/.github/workflows/book.yml
[deny]: https://github.com/paradigmxyz/reth/blob/main/.github/workflows/deny.yml
[sanity]: https://github.com/paradigmxyz/reth/blob/main/.github/workflows/sanity.yml
[project]: https://github.com/paradigmxyz/reth/blob/main/.github/workflows/project.yml
[release]: https://github.com/paradigmxyz/reth/blob/main/.github/workflows/release.yml
[gh-projects]: https://docs.github.com/en/issues/planning-and-tracking-with-projects/automating-your-project/automating-projects-using-actions

62
docs/workflow.md Normal file
View File

@ -0,0 +1,62 @@
## Workflow
### Assigning issues
Before working on an issue, it should be assigned to the person who wants to work on it. For core contributors, this means assigning yourself to the issue, and for external contributors this means asking to be assigned on the issue. This is to avoid double work.
### Pull requests
```mermaid
---
title: A feature or bug fix lives off of main
---
gitGraph
commit
commit
branch feat/cool-feature
checkout feat/cool-feature
commit
commit
checkout main
merge feat/cool-feature
commit
commit
```
- Features and bug fixes live on feature branches off of the main branch, and they are merged onto main as well.
This means that the latest version of reth (which might be unstable) always lives on main.
- Pull requests should not be merged without the review of at least one core contributor. For larger pull requests, at least two is recommended.
- Important pull requests that should be highlighted in the changelog should be marked with the https://github.com/paradigmxyz/reth/labels/M-changelog label.
### Releases
Releases are commits tagged with a version number on main (see [Releases](./release.md)).
```mermaid
---
title: Releases are tags on main
---
gitGraph
commit
commit
branch feat/cool-feature
checkout feat/cool-feature
commit
commit
checkout main
merge feat/cool-feature
commit tag: "v1.2.0"
commit
```
### CI
- Every PR undergoes various checks, including:
- Lints ([clippy], [rustfmt], ...)
- Unit tests
- Fuzz tests
- Integration tests (including peering and a testnet simulation)
- Additionally, each PR is again tested before release by being run every night on a live testnet
[clippy]: https://github.com/rust-lang/rust-clippy
[rustfmt]: https://github.com/rust-lang/rustfmt