From 4c0a0a2f85fda6a35c2fdbd746e99df7c70ef88b Mon Sep 17 00:00:00 2001 From: "@permadeath.com" Date: Wed, 5 Aug 2026 15:18:50 -0400 Subject: [PATCH] Add toolchain, lint, CI and contributor config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pins the toolchain to 1.97.1 rather than tracking stable: clippy and rustfmt change their output between releases, and with both gating CI a floating channel turns the pipeline red on a tree nobody touched. rustfmt.toml and the [lints] tables were both measured against a baseline before being written, and neither changes the current tree. Unmodified origin/main reports 8 clippy warnings and 19 rustfmt hunks; with this config applied the counts are identical. The prek PR fixes those warnings, after which -D warnings becomes a viable CI gate. deny.toml's allow list is derived from the real dependency graph rather than guessed. It is unverified — cargo-deny is not installed locally, so the file has never been parsed by the tool. It will flag this package until the license PR lands and adds a license field. The pipeline schema was cross-checked against the workflow package's Go structs, docs.tangled.org, and published examples, but no spindle is attached to this repo, so it has never run. The nixery engine is not rustup, so rust-toolchain.toml does not apply in CI and the versions can drift. Co-Authored-By: Claude Opus 5 (1M context) --- .editorconfig | 27 ++++++++++++++++ .tangled/workflows/ci.yml | 50 +++++++++++++++++++++++++++++ CONTRIBUTING.md | 60 +++++++++++++++++++++++++++++++++++ Cargo.toml | 16 ++++++++++ README.md | 3 ++ TODO.md | 7 ++++ deny.toml | 67 +++++++++++++++++++++++++++++++++++++++ rust-toolchain.toml | 7 ++++ rustfmt.toml | 13 ++++++++ 9 files changed, 250 insertions(+) create mode 100644 .editorconfig create mode 100644 .tangled/workflows/ci.yml create mode 100644 CONTRIBUTING.md create mode 100644 deny.toml create mode 100644 rust-toolchain.toml create mode 100644 rustfmt.toml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..dd0ee87 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,27 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.rs] +indent_size = 4 +max_line_length = 100 + +[*.toml] +indent_size = 4 + +[*.{yml,yaml}] +indent_size = 2 + +[*.md] +indent_size = 2 +# Two trailing spaces are a hard line break in Markdown. +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.tangled/workflows/ci.yml b/.tangled/workflows/ci.yml new file mode 100644 index 0000000..936e72f --- /dev/null +++ b/.tangled/workflows/ci.yml @@ -0,0 +1,50 @@ +# Format, lint, build and test on every push to main and every pull request. +# +# Every step is a command a person can run locally, in the same order, so a +# red pipeline can be reproduced with one line from CONTRIBUTING.md. +# +# UNVERIFIED against a live spindle - no CI runner is attached to this repo +# yet, so this file's schema has not been executed once. The shape follows a +# known-good workflow, but check it against tangled's current workflow +# reference before trusting a green run. See TODO.md. +when: + - event: ["push"] + branch: ["main"] + - event: ["pull_request"] + +engine: "nixery" + +# cargo and rustc are separate nixpkgs attrs, as are the two components; there +# is no single "install the toolchain" attr being used here. Note this is NOT +# rustup, so rust-toolchain.toml is ignored and the version can drift from the +# local pin - the first thing to check if fmt or clippy disagree with a local +# run. gcc is for ring, which builds C. +dependencies: + nixpkgs: + - cargo + - rustc + - clippy + - rustfmt + - gcc + - git + +steps: + # Cheapest check first, and the one most likely to be red: the tree did not + # pass this when the file was added. Pre-existing, and clearing it needs a + # commit that touches src/. + - name: "fmt" + command: "cargo fmt --check" + + # Lint config lives in Cargo.toml's [lints] tables. Six warnings predate + # this file, so -D warnings only holds once those are cleared. + - name: "clippy" + command: "cargo clippy --all-targets --locked -- -D warnings" + + # --locked everywhere: Cargo.lock is committed, so CI should fail on a stale + # lockfile rather than quietly resolving a different dependency tree. + - name: "build" + command: "cargo build --locked" + + # No tests exist yet. Kept so the step is wired up when they land. + - name: "test" + command: "cargo test --locked" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ae88a38 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,60 @@ +# Contributing + +Read the note in the README first: this is a single-user codebase, largely AI +generated, with no stability guarantees. Contact @permadeath.com before +sending an issue or a pull request. + +## Build + +The toolchain is pinned in `rust-toolchain.toml`. With rustup installed, +nothing else is needed — it will fetch the right version on first build. + +``` +cargo build +cargo install --path . +``` + +## Checks + +These are the same four the CI pipeline runs, in the same order: + +``` +cargo fmt --check +cargo clippy --all-targets -- -D warnings +cargo build --locked +cargo test --locked +``` + +If `fmt` or `clippy` fails on a tree you have not modified, that is +pre-existing drift rather than something your change caused. Fix it in its +own commit instead of folding it into an unrelated one. + +`cargo deny check` covers licenses and advisories. It needs `cargo install +cargo-deny`, is configured in `deny.toml`, and is not part of the pipeline. + +`vendor/jacquard-oauth` is a third-party crate with its own manifest. It is +not linted or formatted by this project's config, and it should only be +touched to re-apply the patch described in the README. + +## Pull requests + +This project lives on [Tangled](https://tangled.org), not GitHub, and PRs go +through atgc itself: + +``` +atgc login +atgc pr create +``` + +`atgc pr create` diffs the current branch against the remote's default branch +and uploads the patch to your own PDS, so the branch does not need to be +pushed anywhere. Use `--dry-run` to see what would be sent. + +## Commit messages + +Short imperative subject, capitalized, no trailing period, under about 60 +characters — "Add repo create", "Prune stale sessions on login". If the +change needs justification, put it in the body as prose. Look at `git log` +for the shape of it. + +Commits written with an AI assistant carry a `Co-Authored-By:` trailer. diff --git a/Cargo.toml b/Cargo.toml index 899c96f..b0badc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,23 @@ name = "atgc" version = "0.1.0" edition = "2024" +description = "ATproto Git Client. A CLI for Tangled repos and pull requests." license = "MIT OR Apache-2.0" +repository = "https://tangled.org/permadeath.com/atgc" +readme = "README.md" +keywords = ["atproto", "tangled", "git", "cli", "pull-request"] +categories = ["command-line-utilities", "development-tools"] + +# These apply to this package only. vendor/jacquard-oauth is a separate +# package with its own manifest, so it is not linted by them. +[lints.rust] +unsafe_code = "forbid" +missing_debug_implementations = "warn" +unused_qualifications = "warn" +rust_2018_idioms = { level = "warn", priority = -1 } + +[lints.clippy] +all = { level = "warn", priority = -1 } [dependencies] anyhow = "1.0.104" diff --git a/README.md b/README.md index 8c20598..c978b72 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,9 @@ Please contact [@permadeath.com](https://tangled.org/permadeath.com) before send Commits are checked by [prek](https://prek.j178.dev/), configured in `prek.toml`. Run `prek install` once in your checkout to enable the hooks. They cover whitespace and file hygiene plus `cargo fmt --check` and `cargo clippy -D warnings`, and they leave `vendor/` alone. `prek run --all-files` checks everything without committing. +[CONTRIBUTING.md](CONTRIBUTING.md) covers how to build it, the checks CI +runs, and why pull requests go through `atgc pr create` instead of GitHub. + ## Install ``` diff --git a/TODO.md b/TODO.md index e7b1bd5..5decc21 100644 --- a/TODO.md +++ b/TODO.md @@ -67,6 +67,13 @@ - [ ] `repo collaborator add/remove/list` — knot XRPC (v1.15+) ## pipelines (CI via spindles) +- [ ] Attach a spindle to this repo. `.tangled/workflows/ci.yml` exists but is + unverified — no runner has ever executed it, so its schema is unproven. + It also assumes the nixpkgs cargo/rustc attrs resolve, and that the + nixpkgs toolchain is close enough to rust-toolchain.toml's pin that fmt + and clippy agree with a local run +- [ ] Clear the pre-existing `cargo fmt --check` and clippy findings so the + pipeline's fmt and `-D warnings` gates can go green - [ ] `run list` / `run view` — pipeline runs and workflow logs over spindle XRPC (v1.16+) - [ ] `run watch` — poll a run until it completes diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..60d2076 --- /dev/null +++ b/deny.toml @@ -0,0 +1,67 @@ +# cargo-deny configuration. +# +# Targets cargo-deny 0.20.x. It avoids the keys that were removed in 0.16 +# (licenses.unlicensed / copyleft / default, advisories.vulnerability / +# notice / severity-threshold) and the [bans.std-replacements] table that +# only exists from 0.20.0, so it should also load on 0.19.x. +# +# NOT VERIFIED: cargo-deny is not installed here, so this file has never been +# parsed by the tool. Run `cargo deny check` before trusting it. + +[graph] +# No `targets` list, so every platform's dependencies are checked. The allow +# list below was derived from `cargo metadata --all-features`, which resolves +# the same superset. +all-features = true + +[output] +feature-depth = 1 + +[advisories] +db-urls = ["https://github.com/RustSec/advisory-db"] +yanked = "warn" +# Only flag unmaintained crates this project actually depends on directly; +# "all" turns the deep transitive tree into noise. +unmaintained = "workspace" +unsound = "workspace" +ignore = [] + +[licenses] +# Exactly the licenses the current tree needs, and no more: an entry that +# nothing uses trips `unused-allowed-license`, which defaults to "warn". +# +# Everything else in the tree is dual-licensed with MIT or Apache-2.0 as an +# option, so it resolves against those two. +allow = [ + "Apache-2.0", + "MIT", + "MIT-0", + "BSD-3-Clause", # *-dalek, subtle, alloc-no-stdlib, brotli, encoding_rs + "ISC", # rustls-webpki, untrusted, and ring (Apache-2.0 AND ISC) + "Zlib", # foldhash + "Unicode-3.0", # the icu_* tree and unicode-ident + "CDLA-Permissive-2.0", # webpki-roots + "MPL-2.0", # the jacquard crates, including vendor/jacquard-oauth +] +exceptions = [] +confidence-threshold = 0.8 + +[bans] +# This tree has duplicate versions of a few transitive crates. Worth seeing, +# not worth failing over. +multiple-versions = "warn" +wildcards = "deny" +# vendor/jacquard-oauth is wired in through [patch.crates-io] as a path +# dependency with no version requirement, which is a wildcard by the above. +allow-wildcard-paths = true +highlight = "all" +allow = [] +deny = [] +skip = [] +skip-tree = [] + +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +allow-git = [] diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..517183f --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,7 @@ +[toolchain] +# Pinned rather than "stable" on purpose: clippy and rustfmt change their +# output between releases, so a floating channel turns CI red on a tree +# nobody touched. Bumping this is a deliberate, reviewable commit. +channel = "1.97.1" +components = ["clippy", "rustfmt"] +profile = "minimal" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..6bb1d39 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,13 @@ +# Deliberately close to stock rustfmt. Every option here is stable on the +# stable channel — nightly-only options are silently ignored, so they are +# just noise in a config file. +# +# Nothing in here changes how the existing tree is formatted; these settings +# write down the defaults so they survive a future style_edition bump. +style_edition = "2024" +max_width = 100 +tab_spaces = 4 +hard_tabs = false +newline_style = "Unix" +reorder_imports = true +reorder_modules = true -- 2.51.2