{"id":19205075,"url":"https://github.com/ggwpez/zepter","last_synced_at":"2026-06-01T00:00:55.135Z","repository":{"id":65724974,"uuid":"594458356","full_name":"ggwpez/zepter","owner":"ggwpez","description":"Analyze, Fix and Format features in your Rust workspace.","archived":false,"fork":false,"pushed_at":"2026-05-31T18:10:36.000Z","size":870,"stargazers_count":97,"open_issues_count":9,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-05-31T19:21:01.268Z","etag":null,"topics":["cargo","clippy","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ggwpez.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-01-28T16:07:37.000Z","updated_at":"2026-05-31T18:10:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"f510f50f-da02-483d-aad6-ef55e06d265b","html_url":"https://github.com/ggwpez/zepter","commit_stats":{"total_commits":164,"total_committers":3,"mean_commits":"54.666666666666664","dds":0.5914634146341464,"last_synced_commit":"5cf66491b8f1ee388e49bc11859ea9de533aa8df"},"previous_names":["ggwpez/zepter","ggwpez/feature"],"tags_count":38,"template":false,"template_full_name":null,"purl":"pkg:github/ggwpez/zepter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggwpez%2Fzepter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggwpez%2Fzepter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggwpez%2Fzepter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggwpez%2Fzepter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ggwpez","download_url":"https://codeload.github.com/ggwpez/zepter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ggwpez%2Fzepter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33753925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cargo","clippy","rust"],"created_at":"2024-11-09T13:11:09.508Z","updated_at":"2026-06-01T00:00:55.129Z","avatar_url":"https://github.com/ggwpez.png","language":"Rust","funding_links":[],"categories":["Developer"],"sub_categories":["Tooling"],"readme":"# Zepter\n\n[![Rust](https://github.com/ggwpez/zepter/actions/workflows/rust.yml/badge.svg)](https://github.com/ggwpez/zepter/actions/workflows/rust.yml)\n[![crates.io](https://img.shields.io/crates/v/zepter.svg)](https://crates.io/crates/zepter)\n![MSRV](https://img.shields.io/badge/MSRV-1.88-informational)\n[![docs.rs](https://img.shields.io/docsrs/zepter)](https://docs.rs/zepter/latest/zepter)\n\nAnalyze, Fix and Format features in your Rust workspace. The goal of this tool is to have this CI ready to prevent common errors with Rust features.\n\n## Install\n\nFrom source code:\n\n```sh\ncargo install zepter -f --locked\n```\n\nAs binary via [`cargo binstall`](https://github.com/cargo-bins/cargo-binstall):  \n\n```sh\ncargo binstall -y zepter\n```\n\n## Commands\n\nzepter\n- *no args*: this is the same as `run`.\n- run: Run a workflow from the config file. Uses `default` if none is specified.\n- format\n  - features: Format features layout and remove duplicates.\n- trace: Trace dependencies paths.\n- lint\n  - propagate-features: Check that features are passed down.\n  - never-enables: A feature should never enable another other.\n  - duplicate-deps: Check that dependencies are not defined in both normal an dev sections.\n  - never-implies *(unstable)*: A feature should never transitively imply another one.\n  - only-enables *(unstable)*: A features should exclusively enable another one.\n  - why-enables *(unstable)*: Find out why a specific feature is enables.\n- debug: *(unstable)* just for quick debugging some stuff.\n- transpose *(unstable)*\n  - dependency\n    - lift-to-workspace: Lifts crate dependencies to the workspace.\n\n## Used By\n\n(Usage does not mean endorsement)\n\n- [alloy-rs/alloy](https://github.com/alloy-rs/alloy/blob/833f9a22ca7c30079d64554d435561877c15267a/.config/zepter.yaml)\n- [paradigmxyz/reth](https://github.com/paradigmxyz/reth/blob/8e7684d49db571891a265239faf8d462e92b23f0/.config/zepter.yaml)\n- [flashbots/rbuilder](https://github.com/flashbots/rbuilder/blob/d22c29b894702d0774e64af70d277ae7bde1da22/zepter.yaml)\n- [paritytech/polkadot-sdk](https://github.com/paritytech/polkadot-sdk/blob/4b83d24f4bc96a7b17964be94b178dd7b8f873b5/.config/zepter.yaml)\n- [chainflip-io/chainflip-backend](https://github.com/chainflip-io/chainflip-backend/blob/a9d15356dc2e41ea953baa4a0ba4c28e4f2c8b40/.zepter.yaml)\n\n## Example - Using Workspace dependencies\n\nCurrently this only works for external dependencies and has some cases where it does not work. However, all the changes\nthat it *does* do, should be correct.\n\nYou can see this in action for example [here](https://github.com/paritytech/polkadot-sdk/pull/3366) or try it out yourself.\nFor example, pulling up all `serde*` crates to the workspace can look like this:\n\n```bash\nzepter transpose dependency lift-to-workspace \"regex:^serde.*\" --ignore-errors\n```\n\nIt will probably print that some versions are not aligned. Zepter has the default behaviour to be cautious to not accidentally\nupdate some dependencies by pulling them up. To get around this and actually do the changes, you can do:\n\n```bash\nzepter transpose dependency lift-to-workspace \"regex:^serde.*\" --ignore-errors --fix --version-resolver=highest\n```\n\nThis will try to select the \"highest\" `SemVer` version of each crate.\n\n## Example - Feature Formatting\n\nTo ensure that your features are in canonical formatting, just run:\n\n```bash\nzepter format features\n# Or shorter:\nzepter f f\n```\n\nThe output will tell you which features are missing formatting:\n\n```pre\nFound 37 crates with unformatted features:\n  polkadot-cli\n  polkadot-runtime-common\n  polkadot-runtime-parachains\n  ...\nRun again with `--fix` to format them.\n```\n\nRe-running with `--fix`/`-f`:\n\n```pre\nFound 37 crates with unformatted features:\n  polkadot-cli\n  polkadot-parachain\n  polkadot-core-primitives\n  polkadot-primitives\n  ...\nFormatted 37 crates (all fixed).\n```\n\nLooking at the diff that this command produces; Zepter assumes a default line width of 80. For one-lined features they will just be padded with spaces:\n\n```patch\n-default = [\n-       \"static_assertions\",\n-]\n+default = [ \"static_assertions\" ]\n```\n\nEntries are sorted, comments are kept and indentation is one tab for your convenience 😊\n\n```patch\n-       # Hi\n-       \"xcm/std\",\n        \"xcm-builder/std\",\n+       # Hi\n+       \"xcm/std\",\n```\n\n## Example - Fixing feature propagation\n\nLet's check that the `runtime-benchmarks` feature is properly passed down to all the dependencies of the `frame-support` crate in the workspace of [Substrate]. You can use commit `395853ac15` to verify it yourself:  \n\n```bash\nzepter lint propagate-feature --feature runtime-benchmarks -p frame-support --workspace\n```\n\nThe output reveals that some dependencies expose the feature but don't get it passed down:  \n\n```pre\ncrate 'frame-support'\n  feature 'runtime-benchmarks'\n    must propagate to:\n      frame-system\n      sp-runtime\n      sp-staking\nFound 3 issues and fixed 0 issues.\n```\n\nWithout the `-p` it will detect many more problems. You can verify this for the [frame-support](https://github.com/paritytech/substrate/blob/ce2cee35f8f0fc5968ea6ffaffa6660dcd008804/frame/support/Cargo.toml#L71) which is indeed missing the feature for `sp-runtime` while [sp-runtime](https://github.com/paritytech/substrate/blob/0b6aec52a90870c999856cd37f7d04789cdd8dfc/primitives/runtime/Cargo.toml#L43) clearly supports it 🤔.\n\nThis can be fixed by appending the `--fix` flag, which results in this diff:\n\n```patch\n-runtime-benchmarks = []\n+runtime-benchmarks = [\n+       \"frame-system/runtime-benchmarks\",\n+       \"sp-runtime/runtime-benchmarks\",\n+       \"sp-staking/runtime-benchmarks\",\n+]\n```\n\nThe auto-fix can be configured to enable specific optional dependencies as non-optional via `--feature-enables-dep=\"runtime-benchmarks:frame-benchmarking\"` for example. In this case the `frame-benchmarking` dependency would enabled as non-optional if the `runtime-benchmarks` feature is enabled.\n\n## Example - Feature tracing\n\nLet's say you want to ensure that specific features are never enabled by default. For this example, we will use the `try-runtime` feature of [Substrate]. Check out branch `oty-faulty-feature-demo` and try:\n\n```bash\nzepter lint never-implies --precondition default --stays-disabled try-runtime --offline --workspace\n```\n\nThe `precondition` defines the feature on the left side of the implication and `stays-disabled` expressing that the precondition never enables this.\n\nErrors correctly with:\n```pre\nFeature 'default' implies 'try-runtime' via path:\n  frame-benchmarking/default -\u003e frame-benchmarking/std -\u003e frame-system/std -\u003e frame-support/wrong -\u003e frame-support/wrong2 -\u003e frame-support/try-runtime\n```\n\nOnly the first path is shown in case there are multiple.\n\n## Example - Dependency tracing\n\nRecently there was a build error in the [Substrate](https://github.com/paritytech/substrate) master CI which was caused by a downstream dependency [`snow`](https://github.com/mcginty/snow/issues/146). To investigate this, it is useful to see *how* Substrate depends on it.  \n\nLet's find out how `node-cli` depends on `snow` (example on commit `dd6aedee3b8d5`):\n\n```bash\nzepter trace node-cli snow\n```\n\nIt reports that `snow` is pulled in from libp2p - good to know. In this case, all paths are displayed.\n\n```pre\nnode-cli -\u003e try-runtime-cli -\u003e substrate-rpc-client -\u003e sc-rpc-api -\u003e sc-chain-spec -\u003e sc-telemetry -\u003e libp2p -\u003e libp2p-webrtc -\u003e libp2p-noise -\u003e snow\n```\n\n## Config Files\n\n⚠️ the syntax for workflows is highly experimental and bound to change.\n\nThe first step is that Zepter checks that it is executed in a rust workspace. Otherwise it fails directly. Then a workflow file is located as follows:\n\n- `$WORKSPACE/zepter.yaml`\n- `$WORKSPACE/.zepter.yaml`\n- `$WORKSPACE/.cargo/zepter.yaml`\n- `$WORKSPACE/.cargo/.zepter.yaml`\n- `$WORKSPACE/.config/zepter.yaml`\n- `$WORKSPACE/.config/.zepter.yaml`\n\nIt uses the first file that is found and errors if none is found. Currently it not possible to overwrite the config in a sub-folder.\n\n### Workflows\n\n\u003e [!NOTE]\n\u003e A production example can be found in the [Polkadot-SDK](https://github.com/paritytech/polkadot-sdk/blob/8ebb5c3319fa52d68f2d76f90f5787a96de254be/.config/zepter.yaml) or in the [`presets`](presets/polkadot.yaml).\n\n\nIt is possible to aggregate the long commands into workflows instead of typing them each time. Zepter tries to locate a config file and run the `default` workflow when it is bare invoked without any arguments.  \nAlternately, it is possible to use `zepter run default`, or any other workflow name.\n\nConfig files can contain workflows like this:\n\n```yaml\nworkflows:\n  default:\n    - [ 'propagate-features', ... ]\n    - ...\n```\n\nIt is also possible to extend previous steps:\n\n```yaml\nworkflows:\n  check:\n    - ...\n  default:\n    - [ $check.0, '--fix' ]\n    - ...\n```\n\n## CI Usage\n\nZepter is currently being used in the [Polkadot-SDK](https://github.com/paritytech/polkadot-sdk/pull/1194) CI to spot missing features.  \nWhen these two experiments prove the usefulness and reliability of Zepter for CI application, then a more streamlined process will be introduced (possibly in the form of CI actions).\n\n## Testing\n\nUnit tests: `cargo test`\nUI and downstream integration tests: `cargo test -- --ignored --nocapture`\n\nEnvironment overwrites exist for the UI tests to:\n- `OVERWRITE`: Update the UI diff locks.\n- `UI_FILTER`: Regex to selectively run UI test.\n- `KEEP_GOING`: Print `FAILED` but don't abort on the first failed UI test.\n\n## Development Principles\n\n- Compile time is human time. Compile time should *always* be substantially below 1 minute.\n- Minimal external dependencies. Reduces source of errors and compile time.\n- Tests. So far, the tool is used since a year extensively in CI and never got a bug report. It should stay like this.\n\n\u003c!-- LINKS --\u003e\n[Cumulus]: https://github.com/paritytech/cumulus\n[Substrate]: https://github.com/paritytech/substrate\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggwpez%2Fzepter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fggwpez%2Fzepter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fggwpez%2Fzepter/lists"}