Contributing

July 10, 2026 · View on GitHub

Thank you for your interest in contributing to yew-nav-link. This document walks you from a fresh clone all the way to a merged pull request. Anything that touches the public API also touches docs/REQUIREMENTS.md and docs/ARCHITECTURE.md — keep all three in sync.

Code of conduct

Participation is governed by CODE_OF_CONDUCT.md. Report unacceptable behaviour via the contact in that file.

Dev environment

You need:

  • Rust stable 1.96+ plus a nightly toolchain (used only for rustfmt):
    rustup default stable
    rustup toolchain install nightly --component rustfmt
    rustup target add wasm32-unknown-unknown
    
  • trunk for the demo crate:
    cargo install --locked trunk
    
  • The CI tooling, mirrored locally so you can reproduce the pipeline:
    cargo install --locked cargo-deny cargo-audit cargo-llvm-cov cargo-nextest \
                            git-cliff
    pip install --user reuse
    

The pre-commit hook in .hooks/pre-commit invokes most of these, so a single git commit runs fmt --check, clippy --pedantic --nursery, cargo deny check, cargo audit, and actionlint.

To wire it in once per clone:

git config core.hooksPath .hooks

Common tasks

TaskCommand
Buildcargo build --workspace --all-features
Format checkcargo +nightly fmt --all -- --check
Lintcargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::pedantic -W clippy::nursery
Testscargo nextest run --all-features
Doc testscargo test --doc --all-features
Coverage reportcargo llvm-cov --all-features --html
Build the democd example && trunk build --release
Serve the democd example && trunk serve then open http://127.0.0.1:3000
Generate CHANGELOG previewgit-cliff --unreleased
Verify SPDX headersreuse lint

Workflow

1. Open or pick an issue

2. Create a branch

Branch names match the issue number:

git checkout -b 123

3. Commit format

git commit -m "#123 feat: add custom class support"

Format is #<issue> <type>: <description> — conventional-commit type with a colon, no (scope). Breaking changes carry a ! on the type (feat!, fix!, refactor!).

TypeUse forTriggers in CHANGELOG
featNew public APIyes — Features
fixBug fixyes — Bug Fixes
docsMarkdown / rustdoc onlyyes — Documentation
refactorInternal restructuring, no behaviour changeyes — Refactoring
ciCI / release pipelineyes — CI
testTest additions or modificationsno
choreMaintenance, dependency bumps, toolingno

git-cliff and release-plz read these prefixes (cliff.toml, release-plz.toml), normalising the #<N> <type>: <desc> form into a conventional-commit subject for the CHANGELOG and the version bump.

4. Open a pull request

  • Title: conventional-commit form matching the commit, e.g. #123 feat: add custom class support. The squash-merge uses the PR title as the subject on main, and release-plz parses it for the changelog and version bump — a bare issue number would be dropped.
  • Body: must include Closes #123 so the issue auto-closes on merge.
  • Reviews: there is no required-reviewer rule on main, but every PR must pass the CI Success aggregate status check before merge — that's enforced by branch protection.
  • Merge style: squash, with branch auto-deleted on merge. The PR title becomes the conventional-commit subject on main; the PR body becomes the commit message body. We keep main linear; force-pushes to main and branch deletion are blocked. Rebase merge stays allowed for the rare case where intermediate commits carry independent value. See docs/BRANCHING.md for the full policy.

Code standards

RuleRequirement
unsafeForbidden in src/ and tests/.
unwrap() / expect()Forbidden outside #[cfg(test)]. Use ?, Option::map_or_else, unwrap_or.
Unnecessary clone()Avoid. Pass references.
Public itemsEvery pub item carries a /// doc comment, plus a doctest where it makes sense.
Line width99 characters (max_width in .rustfmt.toml).
Trailing commasNever (trailing_comma = "Never" in .rustfmt.toml).
EditionRust 2024.
MSRV1.96.

CI overview

.github/workflows/ci.yml runs the following jobs on every PR. The ci-success aggregate must come back green for branch protection to allow merge.

JobRequiredNotes
Extract MSRVyesreads rust-version from Cargo.toml
Checkyesmatrix: 3 toolchains × 3 OSes; also runs clippy (all + no-default features)
Formatyesnightly rustfmt --check
Documentationyescargo doc --all-features with RUSTDOCFLAGS=-D warnings
Public APIyescargo public-api -sss must match docs/public-api.txt
Semver Checksyescargo semver-checks check-release against the last crates.io release
Bookyesmdbook build docs against docs/book.toml
Securityyescargo deny check + cargo audit
REUSE Complianceyesreuse lint
Testyes (skip allowed)cargo nextest + doctests
WASM Testsyeswasm-pack test --headless --chrome --firefox --test wasm
Coverageyes (skip allowed)cargo llvm-cov → Codecov upload
Benchmarksyes (skip allowed)cargo bench --no-run
Example WASM buildyestrunk build --release against example/
E2EyesPlaywright suite under example/e2e/ on chromium + firefox
Lighthouseyesthresholds: perf 0.85, a11y 0.9, best-practices 0.9, SEO 0.9
Actionlintyeslints all workflow YAML
Changelogyes (skip allowed)runs git-cliff

Three more workflows handle deployment side-effects on push to main:

Releasing

Releases are fully autonomous from a contributor's perspective. The maintainer does not edit Cargo.toml or CHANGELOG.md by hand — release-plz does it. The loop:

  1. Land any typed commit on main (feat, fix, docs, refactor, ci, depstest and chore are skipped).
  2. Release-plz workflow opens (or updates) a single release PR titled chore: release vX.Y.Z. The version bump and CHANGELOG.md section are derived from the conventional commits since the last tag.
  3. CI runs on the release PR automatically — the workflow authenticates as the dedicated GitHub App release-plz-yew-nav-link, so PRs it opens trigger downstream workflows the same way human PRs do. (The default GITHUB_TOKEN does not; that is GitHub's anti-recursion policy.)
  4. Maintainer reviews and squash-merges the release PR.
  5. Release-plz workflow runs again on the merge, tags vX.Y.Z, publishes to crates.io, and creates the GitHub Release.
  6. Release attestations fires on the release: published event, generates the SBOM and signed provenance, and attaches them.

Step 4 is the only human action in the chain. There is no manual version-bump path; the Cargo.toml and CHANGELOG.md mutations are exclusively the release PR's diff.

The App identity is configured once per repository — see docs/RELEASE_PLZ_APP_SETUP.md. Two repository secrets carry the credentials: RELEASE_PLZ_APP_ID and RELEASE_PLZ_APP_PRIVATE_KEY. The App has exactly two repository permissions: Contents: read & write and Pull requests: read & write, scoped to this single repo.

For yanking, pre-releases, and the older manual-backfill recipe, see RELEASE.md.

Recognition

All contributors are listed in AUTHORS.md. When your first PR merges, add yourself to that list in a follow-up patch (or ask the maintainer to do it).

References

Questions?

Open a discussion or an issue with the question label.