From 083217e826f2c3568beea0025144adfef2fc83b0 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Thu, 1 Oct 2026 00:32:53 +1300 Subject: [PATCH 1/3] Integrate Bake Agent Context and organize docs --- .agents/conventions.md | 10 ++ publishing.md => .agents/publishing.md | 0 .gitignore | 1 + Cargo.lock | 132 +++++++++++++++++- Cargo.toml | 7 +- bake/Cargo.toml | 9 ++ bake/src/main.rs | 6 + design.md => context/design.md | 0 agent-context.md => context/implementation.md | 11 +- context/rust.md | 109 --------------- conventions.md | 92 ------------ readme.md | 21 ++- releases.md | 6 + 13 files changed, 188 insertions(+), 216 deletions(-) create mode 100644 .agents/conventions.md rename publishing.md => .agents/publishing.md (100%) create mode 100644 bake/Cargo.toml create mode 100644 bake/src/main.rs rename design.md => context/design.md (100%) rename agent-context.md => context/implementation.md (93%) delete mode 100644 context/rust.md delete mode 100644 conventions.md create mode 100644 releases.md diff --git a/.agents/conventions.md b/.agents/conventions.md new file mode 100644 index 0000000..70c3509 --- /dev/null +++ b/.agents/conventions.md @@ -0,0 +1,10 @@ +# Socketry Workspace Conventions + +- Keep shared Rust guidance in the `bake-agent-context` package; this file records workspace-specific boundaries. +- Keep `socketry` as the facade and publish component packages with the `socketry-` prefix. +- Keep `socketry-executor` in `crates/executor`. Split other packages only when they have useful code and a clear dependency boundary. +- New concurrency work uses ordinary futures, not a private coroutine stack per task. The coroutine prototype remains on branch `coroutine`. +- Keep native I/O backends under `scheduler/selector/` and runtime adapters alongside their runtime implementation. +- Pass task owners explicitly when libraries spawn child tasks. Preserve barrier ownership, cancellation, and shutdown behavior. +- Keep public implementation guidance in `context/implementation.md` and architecture decisions in `context/design.md`. +- Keep repository-only conventions and publishing instructions under `.agents/`. diff --git a/publishing.md b/.agents/publishing.md similarity index 100% rename from publishing.md rename to .agents/publishing.md diff --git a/.gitignore b/.gitignore index b83d222..02ae29b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target/ +/.agents/context/ diff --git a/Cargo.lock b/Cargo.lock index 378bfd8..8a8bee5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,6 +59,28 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "bake-agent-context" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "204eeb09dcabe7e7804453d0c8a867d413688d20c2ea972b63577fa74fc91cfb" +dependencies = [ + "serde", + "serde_json", + "socketry-bake", +] + +[[package]] +name = "bake-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b29c86d81ee8f4810e45f8ca9b23c7478bf724fe809cb304d7981bec923912e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "bitflags" version = "2.13.2" @@ -238,6 +260,12 @@ dependencies = [ "libc", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "lazy_static" version = "1.5.0" @@ -250,6 +278,26 @@ version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" +[[package]] +name = "linkme" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3045e122bd98aef8ec3ad58ce84f0791f64e70163d1a02710af4aa11a4d54cc5" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77060ebe535362c3da75682cd17b0431017b6e7c5661e714fc69a7ad017d1301" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -413,6 +461,49 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -457,6 +548,18 @@ dependencies = [ "socketry-executor", ] +[[package]] +name = "socketry-bake" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f78d5c5156533076cb33a2faffb5bc0a491bccec3835d9051d6b109c1ba0046" +dependencies = [ + "bake-macros", + "linkme", + "serde", + "serde_json", +] + [[package]] name = "socketry-executor" version = "0.1.0" @@ -475,6 +578,14 @@ dependencies = [ "tokio", ] +[[package]] +name = "socketry-rust-tasks" +version = "0.0.0" +dependencies = [ + "bake-agent-context", + "socketry-bake", +] + [[package]] name = "syn" version = "2.0.119" @@ -486,6 +597,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "thread_local" version = "1.1.10" @@ -630,7 +752,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -641,7 +763,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -701,3 +823,9 @@ checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ "windows-link 0.1.3", ] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/Cargo.toml b/Cargo.toml index 3816fe9..8405247 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,10 @@ [workspace] -members = ["crates/executor"] +members = ["crates/executor", "bake"] resolver = "3" +[workspace.metadata.bake] +manifest = "bake/Cargo.toml" + [workspace.package] version = "0.1.0" edition = "2024" @@ -16,7 +19,7 @@ description = "Foundational concurrency APIs for Socketry" license.workspace = true repository.workspace = true readme = "readme.md" -include = ["Cargo.toml", "readme.md", "license.md", "conventions.md", "agent-context.md", "design.md", "context/**", "src/**"] +include = ["Cargo.toml", "readme.md", "license.md", "releases.md", "context/**", "src/**"] [dependencies] socketry-executor = { version = "0.1.0", path = "crates/executor", default-features = false } diff --git a/bake/Cargo.toml b/bake/Cargo.toml new file mode 100644 index 0000000..8169693 --- /dev/null +++ b/bake/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "socketry-rust-tasks" +version = "0.0.0" +edition.workspace = true +publish = false + +[dependencies] +bake = { package = "socketry-bake", version = "0.2.1" } +bake-agent-context = "0.1.0" diff --git a/bake/src/main.rs b/bake/src/main.rs new file mode 100644 index 0000000..923317a --- /dev/null +++ b/bake/src/main.rs @@ -0,0 +1,6 @@ +use bake::{Registry, Result}; +use bake_agent_context as _; + +fn main() -> Result<()> { + Registry::discover()?.run() +} diff --git a/design.md b/context/design.md similarity index 100% rename from design.md rename to context/design.md diff --git a/agent-context.md b/context/implementation.md similarity index 93% rename from agent-context.md rename to context/implementation.md index d86ecee..2b893a9 100644 --- a/agent-context.md +++ b/context/implementation.md @@ -1,11 +1,14 @@ -# Agent Context +# Implementation Context -Read conventions.md, design.md and context/rust.md before changing public APIs, -runtime boundaries, package names or workspace layout. +This guide describes the current implementation and its boundaries. Read +[the design guide](design.md) before changing public APIs, runtime boundaries, +package names or workspace layout. Shared Rust development guidance is provided +by the `bake-agent-context` dependency. ## Implemented foundation -- `socketry` is the facade and packages the shared conventions and Rust context. +- `socketry` is the facade for `socketry-executor`. Shared Rust development + guidance is provided by the `bake-agent-context` crate. - `socketry-executor` executes futures using async-task and Crossbeam queues. - Scheduler construction starts worker threads. Tasks require Send + 'static; the pinned future remains stationary while workers may change between polls. diff --git a/context/rust.md b/context/rust.md deleted file mode 100644 index 9fd1d24..0000000 --- a/context/rust.md +++ /dev/null @@ -1,109 +0,0 @@ -# Rust agent context - -Use this guidance when working on Socketry's Rust crates. Read the current -repository's conventions.md and agent-context.md first. Those files establish -project-specific choices and which capabilities are actually implemented. - -## Working from the Ruby designs - -Port behavior, ownership relationships, modularity, and performance choices. -Do not translate Ruby syntax mechanically or introduce a hierarchy of traits -solely to reproduce class inheritance. Prefer data types and composition for -shared state, and traits for capabilities that real consumers need. - -Keep protocol representation and parsing separate from transport and task -scheduling. A protocol library should accept the I/O or owner it needs rather -than silently choosing a runtime for the application. - -Record the exact upstream revision and relevant files for a port. Preserve -license notices and contributor attribution. Explain intentional semantic -differences, especially ownership, cancellation, error handling, and time. - -## Futures and executors - -- Calling an async function constructs a future. Its body runs when polled. -- Poll::Pending returns control to the executor. The future must arrange a - wakeup when it can make progress, and update a stored waker when necessary. -- Treat a wakeup as a request to poll, not proof that the operation is ready. - Preserve wakeups that race with polling or queue transitions. -- Polling must not synchronously block a worker. CPU-intensive work and - blocking system calls need a deliberate execution strategy. -- Do not poll a task concurrently or poll a completed future again. -- Pin preserves an address; Send permits transfer between threads. Neither - implies the other. A future can be Send without being Unpin. -- A Send future can contain non-Send local values during a poll when those - values are not retained across its suspension points. Suspending an - ordinary call stack inside poll invalidates attempts to infer stack - migration safety from the outer future's Send bound. -- The future foundation uses ordinary polling and `.await`. Do not restore - per-task stacks or hidden nested block_on calls as a compatibility shortcut. -- Concrete I/O and timer futures can require particular runtime services even - though they implement the standard Future trait. Trait adaptation does not - replace those services. Call Socketry's native backends selectors; dependencies - such as Tokio may use their own terminology. - -## Tasks and cleanup - -Keep spawning, ownership, execution, cancellation, and completion distinct in -the implementation. An explicit owner controls a child task's lifetime; a -worker polls its future. Libraries spawning children should receive an owner. - -Document what happens when a handle is dropped. A request to stop is different -from confirmation that the task and its children have stopped. Use an awaited -shutdown operation when callers need that confirmation. - -On stable Rust, Drop cannot await. When a future is dropped, ordinary -destructors release retained state, but code after its current await is not -executed. If cleanup needs async work, the runtime must retain and poll the -cleanup work, or the caller must explicitly await it before dropping resources. - -Do not use a destructor alone to justify tasks borrowing their owner's locals. -Account for cancellation, early returns, panics, forgotten futures, and work -already running on another thread before introducing scoped borrowing. - -## I/O and timers - -For completion-based I/O, keep buffers and descriptors alive until the selector -has established the kernel no longer accesses them. A cancellation request or -a dropped waiting future is not that confirmation. Prefer owned buffers in the -lowest-level operation API, and document any copy introduced by stream adapters. - -Reuse stream registration and operation storage where practical. When storage -is reused, ensure a stale completion, waker, or cancellation cannot affect the -new occupant. Invoke user code and wakeups outside selector locks. - -Select concrete implementations with traits, target configuration and Cargo -features. Keep completion operations and readiness fallbacks behind the same -portable contract where the semantics match. Ordinary files need a blocking -pool or completion API; readiness alone does not make their operations async. - -When adapting another runtime, document who keeps it alive and drives events. -Enter its context for each relevant poll, and restore context before returning -Pending. A runtime context guard must not survive across suspension or migration. -Keep registrations attached to their originating runtime and validate resource -identity where different runtime instances are incompatible. - -Use monotonic clocks for deadlines. Keep timer ordering independent of the -runtime, with explicit time inputs suitable for deterministic verification. -Distinguish elapsed deadlines, clock overflow, and cancellation from I/O errors. - -## Implementing changes - -- Inspect existing code and repository status before editing; preserve work - outside the requested change. -- Prefer standard Cargo layout, rustfmt, and readable names. Use lowercase - Markdown documents and start license.md with `# MIT License`. -- Make runtime dependencies optional at the right package boundary. Keep - portable interfaces buildable without the native selector. -- Check generic bounds at public trait boundaries, including whether returned - futures need to be Send. Avoid introducing a Box per operation just to make - a trait object convenient. -- Keep unsafe operations small and state the lifetime, aliasing, pinning, and - thread assumptions they depend on. Use Result for expected failures. -- When verification is requested, cover the behavior being changed using - deterministic synchronization and time. Run platform-dependent operations - on the corresponding platform and report what actually ran. -- Make benchmarks establish allocation counts, contention, and throughput - claims; do not infer a speedup merely from a language change. -- Update documentation and agent context when changing public behavior. - Clearly label proposed APIs that do not yet exist. diff --git a/conventions.md b/conventions.md deleted file mode 100644 index 03173a0..0000000 --- a/conventions.md +++ /dev/null @@ -1,92 +0,0 @@ -# Conventions - -## Repository and packages - -- Use lowercase filenames for Markdown documents. In particular, use - readme.md and license.md. -- The first line of each license.md is `# MIT License`. Preserve attribution - when copying or porting upstream code. -- Keep foundational Rust packages in this repository's Cargo workspace. Give - published component packages the `socketry-` prefix. -- Keep the root Cargo package named `socketry`; use it as the convenient public - facade for the foundational packages. -- Keep package APIs in separately publishable workspace members when they have - a clear dependency and version boundary. -- Keep this file as the record of project-specific conventions and follow it - when adding or changing files. -- Use Cargo's standard `src/`, `tests/`, and `examples/` directories. Keep - architecture-specific implementations in separate modules. -- Treat `socketry-` as the published package prefix. Use semantic module - names within packages; the facade exposes `socketry::executor`. -- Keep the future executor in `crates/executor`, published as `socketry-executor`. - Its public scheduler type is `Scheduler`, also exported as `socketry::Scheduler`. -- Create a new package when it has a useful implementation and a clear - dependency boundary. Keep higher-level protocol packages in their own - repositories when appropriate. - -## Rust code - -- Avoid abbreviations in source code. Prefer clear, consistent names over - shortened names. Preserve names required by external APIs, traits, and - vendored source. -- Follow Rust naming conventions and use the workspace's `cargo fmt` style. -- Keep public APIs small. Prefer private implementation details until a - concrete consumer needs them. -- Use `Result` for expected failures. Document panic conditions and avoid - `unwrap` and `expect` for recoverable failures in library code. -- Prefer standard types and established traits where their semantics fit. - Document why a new abstraction is necessary. -- Use safe Rust by default. Keep unsafe code narrowly scoped, state its - invariants in `SAFETY` comments, and document caller obligations on unsafe - public functions. - -## Runtime boundaries - -- New concurrency work targets ordinary futures, without a coroutine stack - per task. The coroutine implementation is saved on its own branch; see - design.md for the migration plan. -- Protocol code depends on the I/O and task capabilities it uses. Keep - concrete executors, OS selectors, and runtime adapters at explicit boundaries. -- Use `selector` for Socketry's native I/O backends. Keep platform modules - under `scheduler/selector/` and runtime adapters such as Tokio alongside - `scheduler/socketry.rs`. Upstream dependencies may use their own terminology. -- Select native implementations through target configuration and Cargo - features. Share portable contracts and fallback helpers, retaining concrete - future types. Readiness is a socket capability, not a regular-file fallback. -- Pass the task owner explicitly when a library starts child tasks. Scheduler - and barrier ownership follow the same spawning contract. Contextual lookup - may be a convenience at the application boundary. -- Document whether a future, handle, or resource is Send, Sync, or restricted - to a thread. Let Rust check these properties. Do not add unsafe Send or Sync - implementations solely to satisfy a spawning bound. -- Document cancellation at each asynchronous API: what happens before - submission, during execution, after partial progress, and on drop. -- Destructors perform synchronous cleanup or request deferred cleanup. - Methods that wait for shutdown return futures. Do not promise asynchronous - cleanup has completed merely because a value was dropped. - -## Performance and dependencies - -- Make allocation, copying, locking, and reference counting costs explicit - where they affect frequently used operations. Reuse registrations and - buffers when their lifetimes permit it. -- Prefer concrete or generic futures. Introduce boxed futures and dynamic - dispatch at deliberate boundaries rather than on every I/O operation. -- Keep optional runtime and platform dependencies out of portable packages. - Adding a backend must not require every consumer to enable it. -- Distinguish a performance hypothesis from a measured result. A Rust port - inherits an algorithm, not the upstream implementation's benchmark results. - -## Documentation and verification - -- Describe implemented behavior separately from planned behavior. Include - ownership, shutdown, and runtime requirements in public API documentation. -- Keep agent-context.md current when implementation boundaries change. Put - reusable Rust guidance in context/rust.md. -- Put public API tests in `tests/`; keep tests of private invariants beside - the implementation or in a private test module. -- When tests or benchmarks are requested, use deterministic clocks and - synchronization where possible. Record which platforms and configurations - actually ran; distinguish compilation from execution. -- Retain upstream revision, paths, license, and attribution for ports. Keep - verbatim vendor copies separate from translated Rust implementations. diff --git a/readme.md b/readme.md index 24969e6..d666fcd 100644 --- a/readme.md +++ b/readme.md @@ -91,7 +91,8 @@ TCP connect/accept/read/write/readiness, positioned file reads/writes, and sleep are implemented. Regular files use blocking pools except for Linux io_uring. Windows socket readiness uses IOCP/AFD; native overlapped file operations are not implemented. Socketry currently uses async-io's shared readiness reactor -and timers; the io-event timer port remains planned in [design.md](design.md). +and timers; the io-event timer port remains planned in the +[design guide](context/design.md). The io_uring selector owns a dedicated thread, retains buffers until terminal completions, and drains cancellation during shutdown. Connection setup and @@ -104,11 +105,17 @@ The former coroutine implementation is preserved on branch `coroutine`, at commit `b520f3d`. Its native sources, stack allocation, nested synchronous `wait` and task transfer are absent from the future executor. -## Project guidance +## Agent Context -- [Conventions](conventions.md) records the shared Rust and repository style. -- [Agent context](agent-context.md) records current implementation boundaries. -- [Rust context](context/rust.md) provides reusable guidance for other crates. -- [Design](design.md) records runtime boundaries and subsequent work. +This crate includes an [implementation guide](context/implementation.md) and a +[design guide](context/design.md). Shared Rust guidance is provided by the +`bake-agent-context` task dependency. Install it into the repository with: -These documents are included in the root package. +```sh +cargo bake agent:context:install +``` + +Install the launcher once with `cargo install socketry-cargo-bake --locked`. +The generated `.agents/context/` directory is ignored by Git. Repository-only +conventions and publishing instructions live under `.agents/` in the source +checkout. diff --git a/releases.md b/releases.md new file mode 100644 index 0000000..2595b68 --- /dev/null +++ b/releases.md @@ -0,0 +1,6 @@ +# Releases + +## Unreleased + +- Move implementation and design guidance into the package's public context. +- Add Bake Agent Context tasks to the repository's development workspace. From b8603c56ce9c44d290006a86cbe6dbc033f8903d Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Thu, 1 Oct 2026 13:04:45 +1300 Subject: [PATCH 2/3] Move agent context guidance under Contributing. --- readme.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index d666fcd..01ce009 100644 --- a/readme.md +++ b/readme.md @@ -105,7 +105,13 @@ The former coroutine implementation is preserved on branch `coroutine`, at commit `b520f3d`. Its native sources, stack allocation, nested synchronous `wait` and task transfer are absent from the future executor. -## Agent Context +## Contributing + +Please open an issue or pull request on [GitHub](https://github.com/socketry/socketry-rust). + +### Agent Context + +Before contributing, read `agents.md` and the relevant context files it links. If `agents.md` is missing or out of date, run `cargo bake agent:context:install` to install context from dependencies and update the index. This crate includes an [implementation guide](context/implementation.md) and a [design guide](context/design.md). Shared Rust guidance is provided by the From db9bdbde79fb843e441e097caf919a5cf35e8225 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Thu, 1 Oct 2026 14:41:42 +1300 Subject: [PATCH 3/3] Adopt automated GitHub releases. --- .agents/conventions.md | 4 +- .agents/publishing.md | 16 - .github/workflows/publish.yml | 279 ++++++++++++- Cargo.lock | 715 ++++++++++++++++++++++++++++++++-- Cargo.toml | 3 + bake/Cargo.toml | 8 +- bake/src/main.rs | 14 +- readme.md | 18 +- 8 files changed, 991 insertions(+), 66 deletions(-) delete mode 100644 .agents/publishing.md diff --git a/.agents/conventions.md b/.agents/conventions.md index 70c3509..0438116 100644 --- a/.agents/conventions.md +++ b/.agents/conventions.md @@ -1,4 +1,4 @@ -# Socketry Workspace Conventions +# Conventions - Keep shared Rust guidance in the `bake-agent-context` package; this file records workspace-specific boundaries. - Keep `socketry` as the facade and publish component packages with the `socketry-` prefix. @@ -7,4 +7,4 @@ - Keep native I/O backends under `scheduler/selector/` and runtime adapters alongside their runtime implementation. - Pass task owners explicitly when libraries spawn child tasks. Preserve barrier ownership, cancellation, and shutdown behavior. - Keep public implementation guidance in `context/implementation.md` and architecture decisions in `context/design.md`. -- Keep repository-only conventions and publishing instructions under `.agents/`. +- Keep repository-only conventions under `.agents/`; use the Bake Cargo agent context for the shared publishing process. diff --git a/.agents/publishing.md b/.agents/publishing.md deleted file mode 100644 index 49a2a80..0000000 --- a/.agents/publishing.md +++ /dev/null @@ -1,16 +0,0 @@ -# Publishing - -This workspace publishes each Cargo package separately. The GitHub Actions -workflow uses crates.io Trusted Publishing for subsequent releases. - -For each crate's first release, publish manually with an owner token, then -configure its Trusted Publisher on crates.io with: - -- GitHub owner: `socketry` -- Repository: `socketry-rust` -- Workflow: `publish.yml` -- Environment: `crates-io` - -Tag a component release as `socketry-executor-vVERSION` and the facade release -as `socketry-vVERSION`. Publish `socketry-executor` before `socketry`, since -the facade depends on it. diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7a443d4..c8fc2f7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,35 +2,284 @@ name: Publish to crates.io on: push: - tags: - - "socketry-v*" - - "socketry-executor-v*" + branches: + - main + pull_request: + branches: + - main permissions: contents: read jobs: + check: + runs-on: ubuntu-latest + timeout-minutes: 20 + outputs: + release: ${{ steps.detect.outputs.release }} + version: ${{ steps.detect.outputs.version }} + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt + - name: Detect a versioned release change + id: detect + env: + BAKE_BEFORE: ${{ github.event.before || github.event.pull_request.base.sha }} + BAKE_SHA: ${{ github.sha }} + run: | + cargo metadata --format-version 1 --no-deps --locked > "$RUNNER_TEMP/bake-metadata.json" + python3 - <<'PY' + import json + import os + import re + import subprocess + import tomllib + from pathlib import Path + + metadata = json.loads((Path(os.environ["RUNNER_TEMP"]) / "bake-metadata.json").read_text()) + root = Path(metadata["workspace_root"]) + members = set(metadata["workspace_members"]) + packages = [] + for package in metadata["packages"]: + if package["id"] not in members: + continue + publish = package.get("publish") + if publish is False or isinstance(publish, list) and "crates-io" not in publish: + continue + packages.append(package) + if not packages: + raise SystemExit("Workspace has no publishable packages") + + versions = {package["version"] for package in packages} + if len(versions) != 1: + raise SystemExit(f"Publishable workspace packages must share one version: {sorted(versions)}") + version = versions.pop() + pattern = re.compile(r"(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\Z") + match = pattern.fullmatch(version) + if match is None: + raise SystemExit(f"Release version must use stable MAJOR.MINOR.PATCH form: {version}") + current = tuple(map(int, match.groups())) + + before = os.environ["BAKE_BEFORE"] + prior_versions = [] + if before and set(before) != {"0"}: + root_manifest = subprocess.run( + ["git", "show", f"{before}:Cargo.toml"], check=True, capture_output=True, text=True + ).stdout + prior_root = tomllib.loads(root_manifest) + workspace_version = prior_root.get("workspace", {}).get("package", {}).get("version") + for package in packages: + manifest = Path(package["manifest_path"]).relative_to(root).as_posix() + result = subprocess.run( + ["git", "show", f"{before}:{manifest}"], capture_output=True, text=True + ) + if result.returncode != 0: + continue + document = tomllib.loads(result.stdout) + package_version = document.get("package", {}).get("version") + if isinstance(package_version, dict) and package_version.get("workspace") is True: + package_version = workspace_version + if package_version is not None: + prior_versions.append(package_version) + + if prior_versions: + prior_set = set(prior_versions) + if len(prior_set) != 1: + raise SystemExit(f"Previous publishable packages did not share one version: {sorted(prior_set)}") + prior = next(iter(prior_set)) + prior_match = pattern.fullmatch(prior) + if prior_match is None: + raise SystemExit(f"Previous workspace version is not stable MAJOR.MINOR.PATCH: {prior}") + previous = tuple(map(int, prior_match.groups())) + if current < previous: + raise SystemExit(f"Workspace version {version} is lower than previous version {prior}") + if current == previous: + with open(os.environ["GITHUB_OUTPUT"], "a") as output: + output.write("release=false\nversion=\n") + raise SystemExit(0) + + release_notes = (root / "releases.md").read_text() + heading = re.compile(rf"^## v{re.escape(version)}(?:\s|$)", re.MULTILINE) + if heading.search(release_notes) is None: + raise SystemExit(f"releases.md must contain a '## v{version}' heading") + + tag = f"v{version}" + existing = subprocess.run( + ["git", "rev-list", "-n", "1", f"refs/tags/{tag}"], capture_output=True, text=True + ) + if existing.returncode == 0 and existing.stdout.strip() != os.environ["BAKE_SHA"]: + raise SystemExit(f"Tag {tag} already exists at a different commit") + + with open(os.environ["GITHUB_OUTPUT"], "a") as output: + output.write(f"release=true\nversion={version}\n") + PY + - name: Check formatting + run: cargo fmt --all -- --check + - name: Run Clippy + run: cargo clippy --workspace --all-targets --locked -- -D warnings + - name: Run tests + run: cargo test --workspace --locked + publish: + needs: check + if: github.event_name == 'push' && needs.check.outputs.release == 'true' runs-on: ubuntu-latest + timeout-minutes: 20 environment: crates-io + concurrency: release-${{ github.ref }} permissions: - contents: read + contents: write id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 + with: + fetch-depth: 0 - uses: dtolnay/rust-toolchain@stable - - name: Select package from release tag - id: package - shell: bash + - name: Find workspace packages that need publishing + id: packages + env: + BAKE_VERSION: ${{ needs.check.outputs.version }} run: | - case "$GITHUB_REF_NAME" in - socketry-executor-v*) echo "name=socketry-executor" >> "$GITHUB_OUTPUT" ;; - socketry-v*) echo "name=socketry" >> "$GITHUB_OUTPUT" ;; - *) echo "Unsupported release tag: $GITHUB_REF_NAME" >&2; exit 1 ;; - esac + cargo metadata --format-version 1 --no-deps --locked > "$RUNNER_TEMP/bake-metadata.json" + python3 - <<'PY' + import json + import os + from pathlib import Path + from urllib.error import HTTPError, URLError + from urllib.parse import quote + from urllib.request import Request, urlopen + + metadata = json.loads((Path(os.environ["RUNNER_TEMP"]) / "bake-metadata.json").read_text()) + members = set(metadata["workspace_members"]) + packages = [] + for package in metadata["packages"]: + if package["id"] not in members: + continue + publish = package.get("publish") + if publish is False or isinstance(publish, list) and "crates-io" not in publish: + continue + if package["version"] != os.environ["BAKE_VERSION"]: + raise SystemExit(f"{package['name']} has version {package['version']}, expected {os.environ['BAKE_VERSION']}") + packages.append(package) + if not packages: + raise SystemExit("Workspace has no publishable packages") + + existing = [] + for package in packages: + name = package["name"] + url = f"https://crates.io/api/v1/crates/{quote(name, safe='')}/versions" + request = Request(url, headers={"User-Agent": "socketry-bake-publish-workflow"}) + try: + with urlopen(request, timeout=30) as response: + registry = json.load(response) + except HTTPError as error: + if error.code == 404: + continue + raise SystemExit(f"Could not check crates.io for {name}: HTTP {error.code}") + except (URLError, TimeoutError, json.JSONDecodeError) as error: + raise SystemExit(f"Could not check crates.io for {name}: {error}") + versions = registry.get("versions") + if not isinstance(versions, list): + raise SystemExit(f"Unexpected crates.io response while checking {name}") + if any(item.get("num") == os.environ["BAKE_VERSION"] for item in versions if isinstance(item, dict)): + existing.append(name) + + missing = [package["name"] for package in packages if package["name"] not in existing] + with open(os.environ["GITHUB_OUTPUT"], "a") as output: + output.write(f"exclude={json.dumps(existing)}\n") + output.write(f"has_packages={'true' if missing else 'false'}\n") + PY - uses: rust-lang/crates-io-auth-action@v1 id: auth - - name: Publish package - run: cargo publish --package "${{ steps.package.outputs.name }}" + if: steps.packages.outputs.has_packages == 'true' + - name: Publish workspace packages + if: steps.packages.outputs.has_packages == 'true' env: + BAKE_EXCLUDE: ${{ steps.packages.outputs.exclude }} CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} + run: | + python3 - <<'PY' + import json + import os + import subprocess + + arguments = ["cargo", "publish", "--workspace", "--locked"] + for package in json.loads(os.environ["BAKE_EXCLUDE"]): + arguments.extend(["--exclude", package]) + subprocess.run(arguments, check=True) + PY + - name: Create release tag after successful publication + env: + BAKE_VERSION: ${{ needs.check.outputs.version }} + BAKE_SHA: ${{ github.sha }} + run: | + tag="v${BAKE_VERSION}" + if git rev-parse --verify --quiet "refs/tags/${tag}"; then + if [ "$(git rev-list -n 1 "${tag}")" != "${BAKE_SHA}" ]; then + echo "Tag ${tag} already exists at a different commit" >&2 + exit 1 + fi + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git tag -a "${tag}" "${BAKE_SHA}" -m "Release ${tag}" + git push origin "refs/tags/${tag}" + - name: Generate GitHub Release notes + env: + BAKE_VERSION: ${{ needs.check.outputs.version }} + run: | + cargo install socketry-cargo-bake --locked + cargo bake releases:notes "v${BAKE_VERSION}" > "$RUNNER_TEMP/release-notes.md" + - name: Create or update GitHub Release + env: + GH_TOKEN: ${{ github.token }} + BAKE_VERSION: ${{ needs.check.outputs.version }} + BAKE_RELEASE_NOTES: ${{ runner.temp }}/release-notes.md + run: | + python3 - <<'PY' + import json + import os + import subprocess + from pathlib import Path + + tag = f"v{os.environ['BAKE_VERSION']}" + notes = Path(os.environ["BAKE_RELEASE_NOTES"]).read_text() + existing = subprocess.run( + ["gh", "release", "view", tag, "--json", "tagName,name,body,isDraft,url"], + capture_output=True, + text=True, + ) + + if existing.returncode == 0: + release = json.loads(existing.stdout) + if ( + release.get("tagName") == tag + and release.get("name") == tag + and release.get("body", "") == notes + and release.get("isDraft") is False + ): + print(release["url"]) + raise SystemExit(0) + action = "edit" + elif existing.stderr.strip() == "release not found": + action = "create" + else: + raise SystemExit(f"Could not inspect GitHub release {tag}: {existing.stderr.strip()}") + + arguments = ["gh", "release", action, tag, "--title", tag, "--notes-file", "-", "--verify-tag"] + if action == "edit": + arguments.append("--draft=false") + + result = subprocess.run(arguments, input=notes, capture_output=True, text=True) + if result.returncode != 0: + raise SystemExit(f"GitHub release {action} failed: {result.stderr.strip()}") + url = result.stdout.strip() if action == "create" else release["url"] + if not url: + raise SystemExit(f"GitHub release {action} returned no URL") + print(url) + PY diff --git a/Cargo.lock b/Cargo.lock index 8a8bee5..076b4ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aho-corasick" version = "1.1.5" @@ -38,7 +44,7 @@ dependencies = [ "polling", "rustix", "slab", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -59,28 +65,93 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "bake" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb0935384477dcff54df7fc3145427aaed736caa55eec674a89093096f40df7" +dependencies = [ + "bake-macros", + "linkme", + "serde", + "serde_json", +] + [[package]] name = "bake-agent-context" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496c84a9890a2735a88a4e313461beccde1166aa2bd333bd5f4b6daf0c3972ac" +dependencies = [ + "bake", + "serde", + "serde_json", +] + +[[package]] +name = "bake-cargo" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "204eeb09dcabe7e7804453d0c8a867d413688d20c2ea972b63577fa74fc91cfb" +checksum = "5cee1ca7bf582ae8cc5ecc44123b2d32378a3f69b52df11063cc876b6ae36bcb" dependencies = [ + "bake", + "bake-license", + "bake-releases", "serde", "serde_json", - "socketry-bake", + "tempfile", + "toml_edit", + "ureq", +] + +[[package]] +name = "bake-license" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11feb33128721729f6d5b4f89e7a01d2dc84b658a6232a550f4e10db4e2ab990" +dependencies = [ + "bake", + "tempfile", ] [[package]] name = "bake-macros" -version = "0.2.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b29c86d81ee8f4810e45f8ca9b23c7478bf724fe809cb304d7981bec923912e" +checksum = "9d61e078d4ef38e2ba1f5218792234621fe10c75e175dd30ca82d7d91e7b91ef" dependencies = [ "proc-macro2", "quote", "syn 2.0.119", ] +[[package]] +name = "bake-readme" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5872785120621364e5f5dfe45fb577c1f3047c0b46669bbd1ce0a9da9b286d89" +dependencies = [ + "bake", + "serde_json", + "tempfile", +] + +[[package]] +name = "bake-releases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "066f7e695fb0ce89445358a886ee2bf5eba7d10032f0ffb2527e774f6b567191" +dependencies = [ + "bake", + "tempfile", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "2.13.2" @@ -131,6 +202,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crc32fast" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-deque" version = "0.8.8" @@ -156,6 +236,23 @@ version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.14" @@ -163,7 +260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -198,6 +295,26 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures-channel" version = "0.3.34" @@ -243,12 +360,154 @@ dependencies = [ "windows", ] +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + [[package]] name = "hermit-abi" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "io-uring" version = "0.7.15" @@ -304,6 +563,12 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + [[package]] name = "log" version = "0.4.34" @@ -338,6 +603,16 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mio" version = "1.2.3" @@ -346,7 +621,7 @@ checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -355,7 +630,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -370,6 +645,12 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -398,7 +679,16 @@ dependencies = [ "hermit-abi", "pin-project-lite", "rustix", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", ] [[package]] @@ -419,6 +709,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "regex-automata" version = "0.4.18" @@ -436,6 +732,20 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rustix" version = "1.1.5" @@ -446,7 +756,42 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -519,6 +864,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + [[package]] name = "slab" version = "0.4.12" @@ -538,7 +889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -548,18 +899,6 @@ dependencies = [ "socketry-executor", ] -[[package]] -name = "socketry-bake" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f78d5c5156533076cb33a2faffb5bc0a491bccec3835d9051d6b109c1ba0046" -dependencies = [ - "bake-macros", - "linkme", - "serde", - "serde_json", -] - [[package]] name = "socketry-executor" version = "0.1.0" @@ -582,10 +921,26 @@ dependencies = [ name = "socketry-rust-tasks" version = "0.0.0" dependencies = [ + "bake", "bake-agent-context", - "socketry-bake", + "bake-cargo", + "bake-license", + "bake-readme", + "bake-releases", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.119" @@ -608,6 +963,30 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + [[package]] name = "thread_local" version = "1.1.10" @@ -617,6 +996,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tokio" version = "1.53.1" @@ -628,9 +1017,46 @@ dependencies = [ "mio", "pin-project-lite", "socket2", - "windows-sys", + "windows-sys 0.61.2", ] +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.15+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + [[package]] name = "tracing" version = "0.1.44" @@ -686,6 +1112,48 @@ version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "valuable" version = "0.1.1" @@ -698,6 +1166,24 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.9", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "windows" version = "0.61.3" @@ -806,6 +1292,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -815,6 +1310,22 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + [[package]] name = "windows-threading" version = "0.1.0" @@ -824,6 +1335,158 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + [[package]] name = "zmij" version = "1.0.23" diff --git a/Cargo.toml b/Cargo.toml index 8405247..729ef00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,9 @@ resolver = "3" [workspace.metadata.bake] manifest = "bake/Cargo.toml" +[workspace.metadata.bake.release] +reviewers = ["socketry/managers"] + [workspace.package] version = "0.1.0" edition = "2024" diff --git a/bake/Cargo.toml b/bake/Cargo.toml index 8169693..0fcf657 100644 --- a/bake/Cargo.toml +++ b/bake/Cargo.toml @@ -5,5 +5,9 @@ edition.workspace = true publish = false [dependencies] -bake = { package = "socketry-bake", version = "0.2.1" } -bake-agent-context = "0.1.0" +bake = "0.17.0" +bake-agent-context = "0.1.1" +bake-cargo = "0.2.4" +bake-license = "0.1.1" +bake-readme = "0.1.1" +bake-releases = "0.2.1" diff --git a/bake/src/main.rs b/bake/src/main.rs index 923317a..064acc8 100644 --- a/bake/src/main.rs +++ b/bake/src/main.rs @@ -1,5 +1,17 @@ -use bake::{Registry, Result}; +use bake::{Context, Registry, Result}; use bake_agent_context as _; +use bake_cargo as _; +use bake_license as _; +use bake_readme as _; +use bake_releases as _; + +#[bake::task(name = "cargo:after_version_bump")] +fn after_version_bump(context: &mut Context, version: String) -> Result<()> { + context.call("license:update", &[])?; + context.call("releases:update", &[&format!("v{version}")])?; + context.call("readme:update", &[])?; + Ok(()) +} fn main() -> Result<()> { Registry::discover()?.run() diff --git a/readme.md b/readme.md index 01ce009..8d78aee 100644 --- a/readme.md +++ b/readme.md @@ -105,6 +105,14 @@ The former coroutine implementation is preserved on branch `coroutine`, at commit `b520f3d`. Its native sources, stack allocation, nested synchronous `wait` and task transfer are absent from the future executor. +## Releasing + +Prepare a release with `cargo bake cargo:version:patch` (or `minor`, `major`, +or `bump --version X.Y.Z`), then run `cargo bake cargo:release` and open a +pull request. After review and merge, GitHub Actions publishes the release +when the configured `crates-io` environment approves it. See the +[Cargo publishing guide](https://github.com/socketry/bake-cargo-rust/blob/main/context/publishing.md). + ## Contributing Please open an issue or pull request on [GitHub](https://github.com/socketry/socketry-rust). @@ -114,8 +122,10 @@ Please open an issue or pull request on [GitHub](https://github.com/socketry/soc Before contributing, read `agents.md` and the relevant context files it links. If `agents.md` is missing or out of date, run `cargo bake agent:context:install` to install context from dependencies and update the index. This crate includes an [implementation guide](context/implementation.md) and a -[design guide](context/design.md). Shared Rust guidance is provided by the -`bake-agent-context` task dependency. Install it into the repository with: +[design guide](context/design.md). The private `bake/` package links Bake Cargo, +Bake Agent Context, and their companion task crates. Its version-bump hook +updates the license, release notes, and generated Readme sections. Install +dependency context into the repository with: ```sh cargo bake agent:context:install @@ -123,5 +133,5 @@ cargo bake agent:context:install Install the launcher once with `cargo install socketry-cargo-bake --locked`. The generated `.agents/context/` directory is ignored by Git. Repository-only -conventions and publishing instructions live under `.agents/` in the source -checkout. +conventions remain under `.agents/` in the source checkout; publishing guidance +is included in Bake Cargo agent context.