From d06f5148fd5f2632be5b2ad9c895dd34c7b37480 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 6 Oct 2026 01:13:18 +1300 Subject: [PATCH] Align shared project conventions and release v0.19.1. --- .agents/skills/.agent-context-skills.json | 33 -- .../SKILL.md | 79 ----- .../socketry-project-pull-requests/SKILL.md | 65 ---- .../skills/socketry-project-setup/SKILL.md | 101 ------- .github/workflows/test.yml | 12 + Cargo.lock | 41 ++- Cargo.toml | 4 +- agents.md | 108 +------ bake/Cargo.toml | 4 +- context/design.md | 61 +--- context/development.md | 93 ++---- context/task-libraries.md | 283 ++++-------------- context/testing-task-libraries.md | 93 ++---- license.md | 20 +- readme.md | 221 ++++---------- releases.md | 36 ++- 16 files changed, 250 insertions(+), 1004 deletions(-) delete mode 100644 .agents/skills/.agent-context-skills.json delete mode 100644 .agents/skills/socketry-project-github-repository/SKILL.md delete mode 100644 .agents/skills/socketry-project-pull-requests/SKILL.md delete mode 100644 .agents/skills/socketry-project-setup/SKILL.md diff --git a/.agents/skills/.agent-context-skills.json b/.agents/skills/.agent-context-skills.json deleted file mode 100644 index 6e39fb3..0000000 --- a/.agents/skills/.agent-context-skills.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": 1, - "skills": { - "bake-agent-context-usage": { - "package": "bake-agent-context", - "version": "0.3.0" - }, - "socketry-project-github-repository": { - "package": "socketry-project", - "version": "0.3.3" - }, - "socketry-project-pull-requests": { - "package": "socketry-project", - "version": "0.3.3" - }, - "socketry-project-releasing": { - "package": "socketry-project", - "version": "0.3.3" - }, - "socketry-project-setup": { - "package": "socketry-project", - "version": "0.3.3" - }, - "socketry-project-testing": { - "package": "socketry-project", - "version": "0.3.3" - }, - "socketry-project-update": { - "package": "socketry-project", - "version": "0.3.3" - } - } -} \ No newline at end of file diff --git a/.agents/skills/socketry-project-github-repository/SKILL.md b/.agents/skills/socketry-project-github-repository/SKILL.md deleted file mode 100644 index bf78037..0000000 --- a/.agents/skills/socketry-project-github-repository/SKILL.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -name: socketry-project-github-repository -description: Create or maintain GitHub repository metadata, collaboration features, merge settings, and main-branch protections for Socketry projects. Use when setting up a new repository or auditing its existing settings. ---- - -# GitHub Repository Setup - -Use these defaults when creating a Socketry repository. Preserve deliberate -project-specific settings when maintaining an existing repository. - -## Repository metadata - -* Use the canonical Socketry organization and project name. -* Write a short, accurate repository description. -* Set the homepage to the documentation site when one exists. -* Add focused topics for discovery; avoid repeating words already in the - repository name. -* Use `main` as the default branch. - -## Collaboration features - -Enable Issues, Discussions, Pull Requests, Sponsorships, and repository -preservation. Disable Projects and Wiki unless the project has a concrete use -for them. - -Use GitHub issue types consistently: - -* `Bug` for defects and regressions. -* `Feature` for new user-facing capabilities. -* `Task` for maintenance, refactoring, documentation, tests, and release work. - -Prefer organization or repository labels that already exist. Add labels only -when the project needs a reusable classification not covered by issue types or -existing labels. Do not repeat issue type information in issue or pull request -text when GitHub already records it as metadata. - -## Pull requests and commits - -* Disable merge commits; allow squash and rebase merging. -* Suggest updating pull request branches, allow auto-merge, and delete merged - head branches automatically. -* Require contributors to sign off on commits made through GitHub's web - interface. -* Allow comments on individual commits. -* Use Markdown, complete sentences, and a final period for pull request titles - and commit messages. -* Keep most commit messages to one line. Start with what changed. -* Describe pull requests with a short summary followed by the problem and - solution. Use GitHub issue type metadata instead of adding a separate change - type section. - -Use the `socketry-project-pull-requests` skill for the full title, commit, -description, testing, and release note conventions. - -## Branch protection - -Protect `main` and require pull requests with at least one approval. Allow -administrators to bypass these rules for maintenance. Require only stable -checks that are needed for safe auto-merge; do not make experimental, -informational, or unreliable coverage checks mandatory. - -## Apply settings safely - -Use the GitHub CLI for repository changes. Inspect the target first and always -use its full name in commands: - -```sh -gh repo view socketry/PROJECT -``` - -When maintaining an existing repository, inspect its current settings and make -the smallest change that achieves the intended result. Preserve project-specific -settings. Do not rename, archive, transfer, or delete a repository without -explicit approval, and do not disable issues, pull requests, or required checks -without approval. - -The `socketry-project-releasing` skill describes the standard Cargo release -process and links to Bake Cargo task documentation for branch rulesets, -crates.io environment reviewers, and trusted publishing. diff --git a/.agents/skills/socketry-project-pull-requests/SKILL.md b/.agents/skills/socketry-project-pull-requests/SKILL.md deleted file mode 100644 index bc2b952..0000000 --- a/.agents/skills/socketry-project-pull-requests/SKILL.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -name: socketry-project-pull-requests -description: Prepare commits and GitHub pull requests for Socketry Rust projects. Use when writing commit messages, creating or updating a pull request, choosing its issue type, or deciding what to include in the description and release notes. ---- - -# Pull Requests - -Use these conventions when preparing commits or pull requests for Socketry Rust -projects. - -## Titles and commits - -* Pull request titles must use Markdown, be complete sentences, and end with a - full stop. -* Commit messages must use Markdown and end with a full stop. -* The first line of a commit message must focus on what changed. -* Most commit messages should be a single line. -* Keep relevant context in the code itself, such as comments, rather than using - the commit message as a side channel for important details. -* Do not include agent links, attribution footers, generated-by annotations, or - similar metadata in commit messages. - -## Pull request description - -Start with a brief summary, followed by a detailed description of the problem -and solution. Include implementation details that help reviewers understand -the change, link relevant issues when applicable, and include screenshots for -visual changes. - -Use this structure, replacing the guidance with project-specific content: - -```markdown -Briefly summarize the change in 1–3 sentences. - -Describe the problem, context, and solution. Include implementation details -that help reviewers understand the change. Link relevant issues if applicable. -Include screenshots for visual changes. -``` - -Do not add a `Types of Changes` section. Use GitHub issue type metadata for -classification instead. - -## Testing - -Changes should include suitable test coverage. Aim for complete coverage of the -behavior being changed or introduced. If a change directly affects downstream -crates, add or update downstream integration coverage when useful. - -Do not list passing test commands or verification steps in the pull request -description unless they explain an unusual risk, limitation, or manual -validation requirement. - -## Release notes - -For user-visible changes, add a brief entry to `releases.md` following the -release notes guidance provided by `bake-releases`. - -## Issue type - -Set the GitHub issue type correctly when creating or updating a pull request: - -* Use `Bug` for defect fixes and regressions. -* Use `Feature` for new user-facing capabilities. -* Use `Task` for maintenance, refactoring, documentation, tests, release work, - and internal improvements. diff --git a/.agents/skills/socketry-project-setup/SKILL.md b/.agents/skills/socketry-project-setup/SKILL.md deleted file mode 100644 index 5f9acd2..0000000 --- a/.agents/skills/socketry-project-setup/SKILL.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -name: socketry-project-setup -description: Bootstrap a Rust repository with Socketry layout, Bake tasks, agent context, tests, and workflows. Use for a new repository or initial setup. ---- - -# Set Up a Rust Repository - -Use this skill to bootstrap a new Rust repository or add its initial shared -Socketry tooling. For an audit of an established repository, use the -`socketry-project-update` skill. - -## Create the repository - -Use a separate repository for a crate that needs its own version, release notes, -or release tag. Use a Cargo workspace when its packages are meant to ship -together at one version and share one `releases.md` and one `vVERSION` tag. - -Choose the crate name for its public purpose. Crates.io has a flat package -namespace, so use a `socketry-` prefix when needed to identify a Socketry crate. -The repository can use the `-rust` suffix to distinguish it from a related -project in another language. - -Start with the standard Cargo layout and root files described in the -Rust Repository Layout context guide provided by `socketry-project`. Keep the -library's dependencies in the root package and development automation in a -private `bake/` workspace member. - -## Add shared project tasks - -Install the Cargo launcher and bootstrap the private task package: - -```sh -cargo install socketry-cargo-bake --locked -cargo bake --regenerate -``` - -The command creates `bake/`, adds it to the Cargo workspace, and writes a -minimal binary. Add this dependency under the existing `[dependencies]` table in -`bake/Cargo.toml`: - -```toml -socketry-project = "0.3" -``` - -Run regeneration again to link its task registrations: - -```sh -cargo bake --regenerate -``` - -Set release reviewers in the root `Cargo.toml`: - -```toml -[workspace.metadata.bake.release] -reviewers = ["socketry/managers"] -``` - -The `socketry-project` dependency makes the shared tasks available to the -private Bake binary. It also registers `cargo:after_version_bump`, which updates -`license.md`, `releases.md`, and generated sections in `readme.md` after a -version change. -Keep task tooling out of unrelated published libraries. Consumer projects -should depend on `socketry-project` from their private `bake/` package. - -## Agent context - -Follow the [Agent Context section in `readme.md`](../readme.md#agent-context) -to install and discover shared context and skills. Follow -[Conventions](conventions.md#source-and-documentation) for where to keep -package guidance and project-only instructions. The `bake-agent-context` -guide documents installer behavior and options. - -## Set up GitHub - -Configure repository metadata, collaboration features, pull request defaults, -and branch protection using the `socketry-project-github-repository` skill. -Generate the Cargo workflow with `cargo:setup:workflow`; follow the -`socketry-project-releasing` skill before applying rulesets, environment -reviewers, or crates.io trusted publishing. It links to the Bake Cargo Readme -for task-specific details. - -## Test workflows - -Use the `socketry-project-testing` skill for organization-wide testing -expectations. Consult the installed `bake-test-rust` context for canonical -`test.yml` and optional `external.yml` workflows, task setup, coverage options, -and downstream test configuration. - -Use `cargo:setup:workflow` from `bake-cargo` to generate -`.github/workflows/publish.yml`. That workflow checks a release candidate on -pull requests, publishes after merge through the configured `crates-io` -environment, and then creates or updates the matching GitHub Release from -`releases.md`. Follow the `socketry-project-releasing` skill for the release -process and `bake-test-rust` context for workflow and task details. - -## Work on the project - -Keep the root `readme.md` concise and human-focused. Use the project context and -Rust API documentation for detailed implementation guidance. Run the project's -checks before opening a pull request, and update `releases.md` for user-visible -changes. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aabb31a..de705c1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -61,3 +61,15 @@ jobs: if: matrix.runner == 'ubuntu-latest' - name: Run tests and require complete source-region coverage run: cargo bake --locked test:coverage --all-targets true + + test-result: + if: always() + needs: [test, coverage] + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Require successful tests and coverage + env: + JOB_RESULTS: ${{ toJSON(needs) }} + run: | + echo "$JOB_RESULTS" | jq -e 'all(.[]; .result == "success")' diff --git a/Cargo.lock b/Cargo.lock index 26dda4a..0f7cc01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,7 +19,7 @@ dependencies = [ [[package]] name = "bake" -version = "0.19.0" +version = "0.19.1" dependencies = [ "bake-macros", "linkme", @@ -38,7 +38,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml_ng", - "socketry-markdown", + "socketry-markdown 0.1.0", ] [[package]] @@ -52,7 +52,7 @@ dependencies = [ "bake-releases", "serde", "serde_json", - "socketry-markdown", + "socketry-markdown 0.1.0", "tempfile", "toml_edit", "ureq", @@ -65,19 +65,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4877b435fe237311d88e546e8fb2b4a9021aff3550b625b8286e27da0ec693fd" dependencies = [ "bake", - "socketry-markdown", + "socketry-markdown 0.1.0", "tempfile", ] [[package]] name = "bake-macros" -version = "0.19.0" +version = "0.19.1" dependencies = [ "proc-macro2", "quote", "syn 2.0.119", ] +[[package]] +name = "bake-markdown" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be72df839f4db26a93f2fe0659e57ce7998900b9445b04ba1367d51b4ba38587" +dependencies = [ + "bake", + "socketry-markdown 0.3.0", +] + [[package]] name = "bake-readme" version = "0.1.6" @@ -86,7 +96,7 @@ checksum = "24fe3770977781484405d216b11a614a3e26404bb932bdddde718fad206f35c0" dependencies = [ "bake", "serde_json", - "socketry-markdown", + "socketry-markdown 0.1.0", "tempfile", ] @@ -97,7 +107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8439a25fe3a3192a666570d3d907cfb5bff8fdb5df17c92e495bcd4132ce0283" dependencies = [ "bake", - "socketry-markdown", + "socketry-markdown 0.1.0", "tempfile", ] @@ -648,7 +658,7 @@ checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e" [[package]] name = "socketry-cargo-bake" -version = "0.19.0" +version = "0.19.1" dependencies = [ "serde", "serde_json", @@ -666,16 +676,27 @@ dependencies = [ "unicode-id", ] +[[package]] +name = "socketry-markdown" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c02f802fe678b660dd21a6b6130bc2d0eb3423c24b9f26ebddb46514769e788" +dependencies = [ + "regex", + "unicode-id", +] + [[package]] name = "socketry-project" -version = "0.3.3" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5c5a54ff8afc1eb90dfff374dad7550205d28956993b32c1bb7ae49776e1d3c" +checksum = "c2d4af345d5695d21119455e14c348b42267bc0c18eea584b44599d24f42d33e" dependencies = [ "bake", "bake-agent-context", "bake-cargo", "bake-license", + "bake-markdown", "bake-readme", "bake-releases", "bake-test-rust", diff --git a/Cargo.toml b/Cargo.toml index 4ea1987..c048dec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/macros", "crates/cargo-bake", "bake"] resolver = "3" [workspace.package] -version = "0.19.0" +version = "0.19.1" edition = "2024" license = "MIT" repository = "https://github.com/socketry/bake-rust" @@ -65,7 +65,7 @@ name = "bake" serde.workspace = true serde_json.workspace = true linkme.workspace = true -bake-macros = { version = "0.19.0", path = "crates/macros" } +bake-macros = { version = "0.19.1", path = "crates/macros" } [dev-dependencies] tempfile.workspace = true diff --git a/agents.md b/agents.md index baba746..4fa7679 100644 --- a/agents.md +++ b/agents.md @@ -1,104 +1,8 @@ -# Agent +# Agent instructions -## Context +Run `cargo bake agent:context:install` to install dependency context and skills. +Read `.agents/context/index.md`, `.agents/conventions.md`, and the skills relevant +to the task. Keep repository instructions here; the installer preserves this file. -This section links to documentation from installed packages. It is automatically generated and can be refreshed with `cargo bake agent:context:install`. - -**Before working on a package, read the relevant context files below. They contain package-specific guidance and workflows.** - -If these files are missing or dependencies have changed, run `cargo bake agent:context:install` to install them. - -### bake - -Composable, typed development tasks for Rust projects - -#### [Design](.agents/context/bake/design.md) - -The cargo-bake executable asks Cargo for workspace metadata, identifies an -unpublished task binary, and runs it. - -#### [Development Context](.agents/context/bake/development.md) - -This guide summarizes the implementation and task composition in the Bake -repository. - -#### [Structuring Bake Tasks in Crates](.agents/context/bake/task-libraries.md) - -Bake has two common places for task functions: - -### bake-agent-context - -Install context files from Cargo dependencies for coding agents - -#### [Getting Started](.agents/context/bake-agent-context/getting-started.md) - -This guide shows how to add Bake Agent Context tasks to a Rust project and install context from its Cargo dependencies. - -#### [Using and Providing Context](.agents/context/bake-agent-context/usage.md) - -Use Bake Agent Context to discover and install practical guidance shipped in dependency crates. - -#### [Agent Context](.agents/context/bake-agent-context/agent-context.md) - -Keep reusable package guidance separate from repository-only instructions, -and make both easy for agents to discover. - -#### [Rust agent context](.agents/context/bake-agent-context/rust.md) - -Use this shared guidance when working on Socketry's Rust crates. - -#### [Agent Context Specification](.agents/context/bake-agent-context/specification.md) - -Agent Context is a language-agnostic specification for providing and consuming contextual information from software packages to assist AI agents and other automated tools. - -### bake-cargo - -Cargo project and release automation tasks for Bake - -#### [Releasing](.agents/skills/socketry-project-releasing/SKILL.md) - -Follow the shared release process for Socketry Rust projects. - -### bake-readme - -Reusable readme.md maintenance tasks for Bake - -#### [Readme Structure](.agents/context/bake-readme/readme-structure.md) - -Use this guidance when creating or updating a project's readme.md. - -### bake-test-rust - -Reusable Rust test tasks for Bake - -#### [Rust Testing Tasks](.agents/context/bake-test-rust/testing.md) - -Add bake-test-rust as a dependency of the private bake/ package and link it -from bake/src/main.rs: - -### socketry-markdown - -CommonMark compliant markdown parser in Rust with ASTs and extensions - -#### [Markdown Parser Architecture](.agents/context/socketry-markdown/markdown-architecture.md) - -This crate implements a Markdown state machine that tokenizes source, resolves -constructs, and can either compile events directly to HTML or build an mdast -syntax tree. - -### socketry-project - -Shared project conventions and development tasks for Socketry Rust crates - -#### [Socketry Rust Conventions](.agents/context/socketry-project/conventions.md) - -Use these conventions for Rust repositories in the Socketry organization. - -#### [Rust Repository Layout](.agents/context/socketry-project/layout.md) - -Use Cargo's standard structure so contributors can find package code, tests, -examples, and project documentation quickly. - -#### [Rust Testing](.agents/context/socketry-project/testing.md) - -Use Cargo's built-in test command for Rust tests. +Read `context/task-libraries.md` and `context/testing-task-libraries.md` before +changing task registration, library interfaces, or task tests. diff --git a/bake/Cargo.toml b/bake/Cargo.toml index a81c592..00806ed 100644 --- a/bake/Cargo.toml +++ b/bake/Cargo.toml @@ -5,8 +5,8 @@ edition.workspace = true publish = false [dependencies] -socketry-project = ">=0.3.3" -bake = { version = "0.19.0", path = ".." } +socketry-project = ">=0.3.7" +bake = { version = "0.19.1", path = ".." } bake-agent-context = { version = "0.3.0" } bake-test-rust = { version = "0.3.0" } bake-releases = { version = "0.3.0" } diff --git a/context/design.md b/context/design.md index f29fbe3..b064331 100644 --- a/context/design.md +++ b/context/design.md @@ -2,69 +2,26 @@ ## Cargo owns compilation -The cargo-bake executable asks Cargo for workspace metadata, identifies an -unpublished task binary, and runs it. The task binary depends on the core and any -reusable task libraries through normal Cargo dependencies. Cargo handles builds, -dependency resolution, and compiled artifact reuse. +The cargo-bake executable asks Cargo for workspace metadata, identifies an unpublished task binary, and runs it. The task binary depends on the core and any reusable task libraries through normal Cargo dependencies. Cargo handles builds, dependency resolution, and compiled artifact reuse. -This follows the practical direction of Aaron Turon's -[2018 workflow proposal](https://aturon.github.io/tech/2018/04/05/workflows/) -and the [xtask pattern](https://github.com/matklad/cargo-xtask). It uses Cargo's -existing custom commands and metadata; a native Cargo tasks table is unnecessary. +This follows the practical direction of Aaron Turon's [2018 workflow proposal](https://aturon.github.io/tech/2018/04/05/workflows/) and the [xtask pattern](https://github.com/matklad/cargo-xtask). It uses Cargo's existing custom commands and metadata; a native Cargo tasks table is unnecessary. ## Functions define interfaces -The task attribute generates a descriptor and argument adapter next to the original -function. The function remains directly callable. Required scalars are positional; -defaults, Option, and Vec make named arguments. A Vec can opt into unbounded -positional arguments with `#[bake(positional)]`; it consumes bare values until -`::` or the end of the task invocation. Function documentation becomes task help. -The macro checks unsupported signatures and lets Rust check argument traits, -output serialization, and the original function body. +The task attribute generates a descriptor and argument adapter next to the original function. The function remains directly callable. Required scalars are positional; defaults, Option, and Vec make named arguments. A Vec can opt into unbounded positional arguments with `#[bake(positional)]`; it consumes bare values until `::` or the end of the task invocation. Function documentation becomes task help. The macro checks unsupported signatures and lets Rust check argument traits, output serialization, and the original function body. -Each task macro adds a descriptor to a linkme distributed slice. The executable -uses `Registry::discover()` to collect tasks from itself and linked dependencies. -Unnamed tasks in library crates named `bake_*` derive a prefix from the crate -name, removing `bake_` and replacing remaining underscores with colons. Nested -modules extend the namespace; an existing matching module prefix is included -only once. Project binaries and explicit names retain module-based naming, -and a fully qualified explicit name bypasses inference. -The macro emits constant-evaluated name construction from `module_path!()` and -the task attributes. Generated descriptors contain their final names, so manual -registration and discovery agree. Discovery validates metadata and detects -duplicate names across the linked libraries. -Follow [Structuring Bake Tasks in Crates](task-libraries.md) for semantic APIs, -task adapters, and compatibility conventions. Rust omits unused dependencies -from the final link, so each task library must be referenced by the executable -(an import such as `use bake_releases as _;` is enough). This avoids registration -code for each task while keeping task libraries as ordinary Cargo dependencies. +Each task macro adds a descriptor to a linkme distributed slice. The executable uses `Registry::discover()` to collect tasks from itself and linked dependencies. Unnamed tasks in library crates named `bake_*` derive a prefix from the crate name, removing `bake_` and replacing remaining underscores with colons. Nested modules extend the namespace; an existing matching module prefix is included only once. Project binaries and explicit names retain module-based naming, and a fully qualified explicit name bypasses inference. The macro emits constant-evaluated name construction from `module_path!()` and the task attributes. Generated descriptors contain their final names, so manual registration and discovery agree. Discovery validates metadata and detects duplicate names across the linked libraries. Follow [Structuring Bake Tasks in Crates](task-libraries.md) for semantic APIs, task adapters, and compatibility conventions. Rust omits unused dependencies from the final link, so each task library must be referenced by the executable (an import such as `use bake_releases as _;` is enough). This avoids registration code for each task while keeping task libraries as ordinary Cargo dependencies. ## Execution is sequential and contextual -Planning validates all command names and supplied argument values before any task -handler starts. Successful results become the context's previous value. Context -also holds project-local state and builds subprocess commands with a local working -directory. Hooks are ordinary function calls or explicit nested task invocations. +Planning validates all command names and supplied argument values before any task handler starts. Successful results become the context's previous value. Context also holds project-local state and builds subprocess commands with a local working directory. Hooks are ordinary function calls or explicit nested task invocations. -Only the last result is formatted automatically. Tasks decide how to report -progress and diagnostics. A task error stops the chain and includes its task name. -Panics retain ordinary Rust behavior and are not treated as recoverable task errors. +Only the last result is formatted automatically. Tasks decide how to report progress and diagnostics. A task error stops the chain and includes its task name. Panics retain ordinary Rust behavior and are not treated as recoverable task errors. -Automatic formatting goes through the registered `output` task. It receives the -last task's result as an injected value. Explicit `output` commands therefore work -in chains, write to stdout or a project-relative file, and return the original value -for further processing. Projects can replace the registered output task. A task -that already emits output can mark itself with `#[bake::task(output)]` to suppress -the automatic formatter. The `null` task consumes a result without displaying it. +Automatic formatting goes through the registered `output` task. It receives the last task's result as an injected value. Explicit `output` commands therefore work in chains, write to stdout or a project-relative file, and return the original value for further processing. Projects can replace the registered output task. A task that already emits output can mark itself with `#[bake::task(output)]` to suppress the automatic formatter. The `null` task consumes a result without displaying it. ## Scope -The initial release provides synchronous tasks, link-time discovery, typed -command-line values, reusable libraries, help, structured output, composition, -and release-note tasks. It does not infer a dependency graph: task libraries must -be Cargo dependencies and referenced by the executable to be linked. Async execution, -richer parsers, and additional release automation can be added when a concrete task -needs them. +The initial release provides synchronous tasks, link-time discovery, typed command-line values, reusable libraries, help, structured output, composition, and release-note tasks. It does not infer a dependency graph: task libraries must be Cargo dependencies and referenced by the executable to be linked. Async execution, richer parsers, and additional release automation can be added when a concrete task needs them. -No Ruby implementation files are vendored. The release task behavior is inspired -by Samuel Williams's MIT-licensed bake-releases; the Rust implementation is original. +No Ruby implementation files are vendored. The release task behavior is inspired by Samuel Williams's MIT-licensed bake-releases; the Rust implementation is original. diff --git a/context/development.md b/context/development.md index 5130fb0..fb44870 100644 --- a/context/development.md +++ b/context/development.md @@ -1,67 +1,43 @@ # Development Context -This guide summarizes the implementation and task composition in the Bake -repository. It complements the public usage guides in this directory. +This guide summarizes the implementation and task composition in the Bake repository. It complements the public usage guides in this directory. ## Purpose -Bake is a Cargo-compatible task runner inspired by Samuel Williams's Ruby Bake. -The project-local task binary contains ordinary typed Rust functions. The launcher -discovers and runs that binary through Cargo. `#[bake::task]` registers functions -for `Registry::discover()`. Library crates named `bake_*` supply default task -prefixes, extended by nested Rust modules. Project binaries keep module-based -naming. Task library dependencies must be referenced by the executable to make -the linker include them. +Bake is a Cargo-compatible task runner inspired by Samuel Williams's Ruby Bake. The project-local task binary contains ordinary typed Rust functions. The launcher discovers and runs that binary through Cargo. `#[bake::task]` registers functions for `Registry::discover()`. Library crates named `bake_*` supply default task prefixes, extended by nested Rust modules. Project binaries keep module-based naming. Task library dependencies must be referenced by the executable to make the linker include them. ## Source map - src/arguments.rs: parameter metadata, typed validation, command-line parsing. - src/task.rs: task descriptor and handler interface. -- src/task_name.rs: constant-evaluated crate and module namespace inference. +- src/task\_name.rs: constant-evaluated crate and module namespace inference. - src/registry.rs: registration, namespace imports, command planning, help and output. - src/output.rs: replaceable default output, raw/JSON/NDJSON formatting, and null sink. - src/context.rs: shared state, project root, previous result, nested calls. - crates/macros/: task attribute and generated adapters; re-exported by bake. - crates/cargo-bake/: Cargo discovery and process launcher; independent of the core. -- [bake-releases-rust](https://github.com/socketry/bake-releases-rust): - release-document parsing and reusable notes/update tasks. -- [bake-cargo-rust](https://github.com/socketry/bake-cargo-rust): - Cargo workspace, version, GitHub release, and publishing tasks. -- [bake-license-rust](https://github.com/socketry/bake-license-rust): - license documents and Rust source copyright maintenance. -- [bake-agent-context-rust](https://github.com/socketry/bake-agent-context-rust): - dependency context discovery, inspection, and installation. +- [bake-releases-rust](https://github.com/socketry/bake-releases-rust): release-document parsing and reusable notes/update tasks. +- [bake-cargo-rust](https://github.com/socketry/bake-cargo-rust): Cargo workspace, version, GitHub release, and publishing tasks. +- [bake-license-rust](https://github.com/socketry/bake-license-rust): license documents and Rust source copyright maintenance. +- [bake-agent-context-rust](https://github.com/socketry/bake-agent-context-rust): dependency context discovery, inspection, and installation. - bake/: this repository's task binary and examples of composition. -The task binary links reusable task libraries through dependencies declared in -`bake/Cargo.toml`; each library must be referenced by the executable so its -registered tasks are linked into the binary. +The task binary links reusable task libraries through dependencies declared in `bake/Cargo.toml`; each library must be referenced by the executable so its registered tasks are linked into the binary. ## Important boundaries -- Task registration uses linkme's linker inventory. It is static, not a dynamic - plugin ABI. Dependencies that contribute tasks must be referenced in the task - binary, e.g. `use bake_releases as _;`. -- The macro resolves names through Rust constant evaluation. Generated descriptors - have their final names before discovery; the registry validates and collects them. +- Task registration uses linkme's linker inventory. It is static, not a dynamic plugin ABI. Dependencies that contribute tasks must be referenced in the task binary, e.g. `use bake_releases as _;`. +- The macro resolves names through Rust constant evaluation. Generated descriptors have their final names before discovery; the registry validates and collects them. - The launcher reads Cargo metadata format 1; it does not link Cargo internals. - Package-level configuration takes precedence over workspace-level configuration. - The core is synchronous. An async runtime can be owned by an individual task. -- A chain shares one Context. Nested calls use full registered names and update - previous() on success. Calls are limited to 64 nested invocations. -- The registry includes `output` and `null`. It invokes `output` after the last task - unless that task handles output. Reusable namespace imports skip these built-ins. -- `#[bake(input)] value: bake::Value` injects the previous result. The default - output task returns that result after writing it, so later tasks can reuse it. -- Supplied values are validated before execution, then parsed by generated adapters. - Default expressions run at invocation time. -- Required scalars are positional; `Option` and `Vec` are named by default. The - opt-in positional `Vec` is unbounded and ends only at `::` or the end of the - invocation, so it must be the last positional argument. -- Release documents use unindented ATX headings and fenced code blocks. This is - a deliberate narrow document format, not a complete CommonMark parser. -- The release updater replaces the document through a temporary file in the same - directory, preserving file permissions. It follows an existing symlink to its target. +- A chain shares one Context. Nested calls use full registered names and update previous() on success. Calls are limited to 64 nested invocations. +- The registry includes `output` and `null`. It invokes `output` after the last task unless that task handles output. Reusable namespace imports skip these built-ins. +- `#[bake(input)] value: bake::Value` injects the previous result. The default output task returns that result after writing it, so later tasks can reuse it. +- Supplied values are validated before execution, then parsed by generated adapters. Default expressions run at invocation time. +- Required scalars are positional; `Option` and `Vec` are named by default. The opt-in positional `Vec` is unbounded and ends only at `::` or the end of the invocation, so it must be the last positional argument. +- Release documents use unindented ATX headings and fenced code blocks. This is a deliberate narrow document format, not a complete CommonMark parser. +- The release updater replaces the document through a temporary file in the same directory, preserving file permissions. It follows an existing symlink to its target. ## Useful commands @@ -83,29 +59,12 @@ cargo bake --locked greet Samuel --excited true cargo bake --locked releases:notes Unreleased ``` -The private task binary links `bake-test-rust`, which registers `test` and -`test:external`. Selected downstream Bake projects are listed in the root -`Cargo.toml` under `[workspace.metadata.bake.test.external]`. The external task -checks those projects against the local workspace crates and keeps their -checkouts under the ignored `external/` directory. The External Tests workflow -runs the same task on pushes and pull requests. - -The Test workflow runs `cargo bake --locked test` on macOS and the coverage task -on Ubuntu. Windows runs `cargo test --workspace --locked` directly because the -task runner is part of this workspace and Windows cannot replace its executable -while it is running. The Ubuntu job also runs formatting and Clippy. Coverage -runs workspace and documentation tests, invokes the optional `test:before` hook, -and requires 100% line coverage. The External Tests workflow is separate because -this workspace lists selected downstream projects in -`[workspace.metadata.bake.test.external]`. - -Follow the current session's instructions about adding or running tests. Use ---offline with a populated Cargo cache when network access is unavailable. - -Inspect actual workflow results before claiming verification on another -platform. - -For release preparation and registry setup, follow the shared -[Releasing skill](https://github.com/socketry/socketry-project-rust/blob/main/context/releasing.md). -Publishing must be explicitly requested; ordinary development commands do not -release anything. +The private task binary links `bake-test-rust`, which registers `test` and `test:external`. Selected downstream Bake projects are listed in the root `Cargo.toml` under `[workspace.metadata.bake.test.external]`. The external task checks those projects against the local workspace crates and keeps their checkouts under the ignored `external/` directory. The External Tests workflow runs the same task on pushes and pull requests. + +The Test workflow runs `cargo bake --locked test` on macOS and the coverage task on Ubuntu. Windows runs `cargo test --workspace --locked` directly because the task runner is part of this workspace and Windows cannot replace its executable while it is running. The Ubuntu job also runs formatting and Clippy. Coverage runs workspace and documentation tests, invokes the optional `test:before` hook, and requires 100% line coverage. The External Tests workflow is separate because this workspace lists selected downstream projects in `[workspace.metadata.bake.test.external]`. + +Follow the current session's instructions about adding or running tests. Use --offline with a populated Cargo cache when network access is unavailable. + +Inspect actual workflow results before claiming verification on another platform. + +For release preparation and registry setup, follow the shared [Releasing skill](https://github.com/socketry/socketry-project-rust/blob/main/context/releasing.md). Publishing must be explicitly requested; ordinary development commands do not release anything. diff --git a/context/task-libraries.md b/context/task-libraries.md index 83be40e..6608573 100644 --- a/context/task-libraries.md +++ b/context/task-libraries.md @@ -1,27 +1,17 @@ # Structuring Bake Tasks in Crates -Define reusable automation as semantic Rust APIs and expose those operations as -Bake tasks with stable command names. +Define reusable automation as semantic Rust APIs and expose those operations as Bake tasks with stable command names. -For Socketry projects, follow the -[crate and module conventions](https://github.com/socketry/socketry-project-rust/blob/main/context/conventions.md) -and [source layout](https://github.com/socketry/socketry-project-rust/blob/main/context/layout.md) -provided by `socketry-project`. This guide explains how those conventions apply -to Bake task libraries. See [Testing Task Libraries](testing-task-libraries.md) -for verification at the library, task, and executable boundaries. +For Socketry projects, follow the [crate and module conventions](https://github.com/socketry/socketry-project-rust/blob/main/context/conventions.md) and [source layout](https://github.com/socketry/socketry-project-rust/blob/main/context/layout.md) provided by `socketry-project`. This guide explains how those conventions apply to Bake task libraries. See [Testing Task Libraries](testing-task-libraries.md) for verification at the library, task, and executable boundaries. Bake has two common places for task functions: -- A project's unpublished `bake/` binary crate holds tasks specific to that - project. The `cargo-bake` launcher compiles and runs it. -- A normal library crate can export reusable tasks alongside its Rust API. Other - Bake binaries discover those tasks when they depend on and link that library. +- A project's unpublished `bake/` binary crate holds tasks specific to that project. The `cargo-bake` launcher compiles and runs it. +- A normal library crate can export reusable tasks alongside its Rust API. Other Bake binaries discover those tasks when they depend on and link that library. ## Keep project tasks in a small binary crate -For project-specific automation, put the task functions in the task binary or -its child modules. The crate can stay unpublished and separate from the project's -released libraries: +For project-specific automation, put the task functions in the task binary or its child modules. The crate can stay unpublished and separate from the project's released libraries: ```text project/ @@ -41,9 +31,7 @@ cargo install socketry-cargo-bake --locked cargo bake --regenerate ``` -The command creates `bake/`, adds it to the workspace, and generates a minimal -binary. Later runs refresh its generated task-library links while preserving -the project's task source. +The command creates `bake/`, adds it to the workspace, and generates a minimal binary. Later runs refresh its generated task-library links while preserving the project's task source. `main.rs` can declare modules and start discovery: @@ -55,57 +43,30 @@ fn main() -> bake::Result<()> { } ``` -Task functions in `release.rs` are ordinary Rust functions annotated with -`#[bake::task]`. Keep them next to the project automation they implement. Split -growing modules by domain, and preserve existing command names when moving -functions between modules. +Task functions in `release.rs` are ordinary Rust functions annotated with `#[bake::task]`. Keep them next to the project automation they implement. Split growing modules by domain, and preserve existing command names when moving functions between modules. ## Start with a semantic Rust interface -Put reusable tasks in the library crate that owns the behavior they automate. -Give ordinary Rust callers an interface expressed in the library's domain: - -- Use functions for operations such as `extract_notes(document, version)` or - `update_document(document, version)`. -- Use objects when they own meaningful state, such as an `Installer` that holds - discovered packages and supports `install_all` and `install_package`. -- Accept the paths, documents, options, and collaborators an operation needs. - Keep project-root resolution and task invocation at the Bake boundary. -- Return domain values and errors that callers can inspect. Use descriptive - result types when several related values form one result. - -Standardize vocabulary, inputs, results, and failure semantics where libraries -perform the same kind of operation. For example, `list` enumerates available -items, `show` retrieves selected content, and `update` maintains an existing -resource. Use `plan` and `apply` when inspecting proposed changes separately -from applying them is useful. Add only the operations the domain needs. - -Preserve domain-specific signatures. Add a shared trait when real consumers -need interchangeable implementations. Use options structs for coherent sets -of options and objects for meaningful state; small operations can remain -functions. - -Follow Socketry's rule that the crate name supplies the root Rust namespace. -Re-export the main API from private implementation modules. Public modules -should identify a meaningful part of the domain. Do not add a public wrapper -such as `bake_releases::releases` solely to obtain a command prefix. +Put reusable tasks in the library crate that owns the behavior they automate. Give ordinary Rust callers an interface expressed in the library's domain: + +- Use functions for operations such as `extract_notes(document, version)` or `update_document(document, version)`. +- Use objects when they own meaningful state, such as an `Installer` that holds discovered packages and supports `install_all` and `install_package`. +- Accept the paths, documents, options, and collaborators an operation needs. Keep project-root resolution and task invocation at the Bake boundary. +- Return domain values and errors that callers can inspect. Use descriptive result types when several related values form one result. + +Standardize vocabulary, inputs, results, and failure semantics where libraries perform the same kind of operation. For example, `list` enumerates available items, `show` retrieves selected content, and `update` maintains an existing resource. Use `plan` and `apply` when inspecting proposed changes separately from applying them is useful. Add only the operations the domain needs. + +Preserve domain-specific signatures. Add a shared trait when real consumers need interchangeable implementations. Use options structs for coherent sets of options and objects for meaningful state; small operations can remain functions. + +Follow Socketry's rule that the crate name supplies the root Rust namespace. Re-export the main API from private implementation modules. Public modules should identify a meaningful part of the domain. Do not add a public wrapper such as `bake_releases::releases` solely to obtain a command prefix. ## Expose operations as Bake tasks -A task function adapts command arguments and execution context to the semantic -API. Keep substantial parsing, transformations, and filesystem or subprocess -operations in the implementation that ordinary Rust callers use. The adapter -can resolve paths, select options, obtain context state, invoke hooks, and -choose the task result. +A task function adapts command arguments and execution context to the semantic API. Keep substantial parsing, transformations, and filesystem or subprocess operations in the implementation that ordinary Rust callers use. The adapter can resolve paths, select options, obtain context state, invoke hooks, and choose the task result. -When an operation already has a suitable task signature, annotate it directly. -Separate adapters are useful when the library accepts borrowed values, owns -state, or needs a different calling interface. Avoid forwarding layers that -add no meaning. Task functions remain callable as ordinary Rust functions; -their visibility should reflect the intended Rust API. +When an operation already has a suitable task signature, annotate it directly. Separate adapters are useful when the library accepts borrowed values, owns state, or needs a different calling interface. Avoid forwarding layers that add no meaning. Task functions remain callable as ordinary Rust functions; their visibility should reflect the intended Rust API. -For example, this illustrative `bake_releases` library puts the task in -`lib.rs` and keeps file reading and document parsing in private modules: +For example, this illustrative `bake_releases` library puts the task in `lib.rs` and keeps file reading and document parsing in private modules: ```text src/ @@ -153,22 +114,13 @@ pub fn read_notes(path: &Path, version: &str) -> Result { } ``` -The parser in `document.rs` supplies -`extract_notes<'a>(document: &'a str, version: &str) -> Result<&'a str>`. -The example illustrates a proposed library layout; it does not describe the -current exports of `bake-releases`. -Rust callers can use the parser, call `read_notes` with an explicit path, or -call the Bake adapter. They do not need to construct a `Context` to read a file. +The parser in `document.rs` supplies `extract_notes<'a>(document: &'a str, version: &str) -> Result<&'a str>`. The example illustrates a proposed library layout; it does not describe the current exports of `bake-releases`. Rust callers can use the parser, call `read_notes` with an explicit path, or call the Bake adapter. They do not need to construct a `Context` to read a file. ## Let the library define the default task namespace -Use domain namespaces and meaningful operations, such as `releases:notes`, -`license:update`, and `cargo:version:bump`. Existing task names and argument -contracts are compatibility boundaries. +Use domain namespaces and meaningful operations, such as `releases:notes`, `license:update`, and `cargo:version:bump`. Existing task names and argument contracts are compatibility boundaries. -For a library crate whose Rust name starts with `bake_`, `#[bake::task]` -derives a namespace by removing that prefix and replacing the remaining -underscores with colons. It then appends nested modules and the function name: +For a library crate whose Rust name starts with `bake_`, `#[bake::task]` derives a namespace by removing that prefix and replacing the remaining underscores with colons. It then appends nested modules and the function name: | Task definition | Task name | | --- | --- | @@ -177,173 +129,68 @@ underscores with colons. It then appends nested modules and the function name: | `bake_agent_context::skill_list` with `name = "agent:context:skill:list"` | `agent:context:skill:list` | | `bake_cargo::version::bump` with `#[bake::task]` | `cargo:version:bump` | -The crate supplies the Rust namespace and the default command prefix. An -additional public `releases` module would repeat the domain already named by -`bake_releases`; likewise, a public `context` module would repeat the final -segment of `bake_agent_context`. Keep task placement close to the semantic -operations it exposes. Use the default attribute when the defining crate, -modules, and function already express the intended task name; use a full -explicit name when a meaningful module path would otherwise add an unwanted -command segment or the function name does not express the command's semantic -form. - -Underscores in module names retain their existing hyphen conversion; function -names remain unchanged. The namespace uses the defining Rust crate name, even -when a consumer renames its dependency. Re-exporting a function does not change -its defining module path. For existing code whose modules already start with the -complete crate-derived namespace, inference includes the prefix only once. New -task libraries should avoid that redundant module layer; for example, define -`notes` in `bake_releases` instead of `bake_releases::releases`. - -Project binary targets keep their existing module-based naming, including -binaries whose names start with `bake_`. Cargo identifies those targets through -`CARGO_BIN_NAME`. Libraries without the `bake_` prefix also keep module-based -naming; their crate name does not become a command prefix. - -Use an explicit `name` when a command intentionally differs from the default -or needs to remain stable across implementation moves. Explicit names retain -their existing behavior: a name containing `:` is used as-is, while a short -name receives only its defining module's namespace. Neither receives a new -crate-derived prefix. Thus a root function marked `#[bake::task(name = "test")]` -still exports `test` from `bake_test_rust`. A function marked -`#[bake::task(name = "releases:notes")]` keeps that command from any module. - -The attribute generates argument conversion, a descriptor, and registration. -The library depends on `bake` to use these facilities. No additional registration -framework or common task-library trait is needed. - -Reusable task libraries should declare `bake = "0"` so Cargo can resolve their -registry dependency to the Bake 0.x version selected by the consuming task -binary. Project-local task binaries can select a specific minor release, such -as `bake = "0.18"`. - -Names are resolved during compilation from the defining `module_path!()`, the -attribute, and Cargo's binary-target metadata. The generated `notes_task()` -descriptor already contains `releases:notes`; registering it manually produces -the same name as `Registry::discover()`. Discovery collects descriptors, -validates their metadata, and detects collisions across linked crates. +The crate supplies the Rust namespace and the default command prefix. An additional public `releases` module would repeat the domain already named by `bake_releases`; likewise, a public `context` module would repeat the final segment of `bake_agent_context`. Keep task placement close to the semantic operations it exposes. Use the default attribute when the defining crate, modules, and function already express the intended task name; use a full explicit name when a meaningful module path would otherwise add an unwanted command segment or the function name does not express the command's semantic form. + +Underscores in module names retain their existing hyphen conversion; function names remain unchanged. The namespace uses the defining Rust crate name, even when a consumer renames its dependency. Re-exporting a function does not change its defining module path. For existing code whose modules already start with the complete crate-derived namespace, inference includes the prefix only once. New task libraries should avoid that redundant module layer; for example, define `notes` in `bake_releases` instead of `bake_releases::releases`. + +Project binary targets keep their existing module-based naming, including binaries whose names start with `bake_`. Cargo identifies those targets through `CARGO_BIN_NAME`. Libraries without the `bake_` prefix also keep module-based naming; their crate name does not become a command prefix. + +Use an explicit `name` when a command intentionally differs from the default or needs to remain stable across implementation moves. Explicit names retain their existing behavior: a name containing `:` is used as-is, while a short name receives only its defining module's namespace. Neither receives a new crate-derived prefix. Thus a root function marked `#[bake::task(name = "test")]` still exports `test` from `bake_test_rust`. A function marked `#[bake::task(name = "releases:notes")]` keeps that command from any module. + +The attribute generates argument conversion, a descriptor, and registration. The library depends on `bake` to use these facilities. No additional registration framework or common task-library trait is needed. + +Reusable task libraries should declare `bake = "0"` so Cargo can resolve their registry dependency to the Bake 0.x version selected by the consuming task binary. Project-local task binaries can select a specific minor release, such as `bake = "0.19"`. + +Names are resolved during compilation from the defining `module_path!()`, the attribute, and Cargo's binary-target metadata. The generated `notes_task()` descriptor already contains `releases:notes`; registering it manually produces the same name as `Registry::discover()`. Discovery collects descriptors, validates their metadata, and detects collisions across linked crates. ## Keep task contracts predictable -- Use typed parameters. Required scalars are positional by default; defaults, - `Option`, and `Vec` produce named options. Use `#[bake(named)]` for a required - named option. A `Vec` can opt into positional variadic arguments with - `#[bake(positional)]`; it must be the last positional parameter, and callers - must use `::` before a following task. Document arguments with `help`. -- Resolve project-relative paths against `context.root()`. Use - `context.command(...)` for project subprocesses, or pass an explicit working - directory to an operation acting on another checkout. Avoid changing the - process-wide working directory or environment. -- Validate inputs before making changes. Include the affected file, package, - or command in errors when that context helps identify the failure. Propagate - failures from operations and hooks. -- Return the semantic result. Text is appropriate for release notes; a list - or serializable result struct suits package metadata or an update summary. - Use `()` when there is no useful result. Avoid making callers parse a success - message to recover counts, paths, or other structured data. Existing output - shapes also need compatibility consideration when migrating a library. -- Let Bake's `output` task format the final result. Send progress and diagnostics - to stderr. Use `#[bake::task(output)]` only when the task owns its final output; - subprocess progress alone does not require it. - -Use ordinary Rust calls to compose implementation operations. Use -`context.call(...)` where composition is intentionally through registered -tasks, including project-defined hooks. Use `call_if_registered` for optional -hooks and document when they run and which arguments they receive. Libraries -can cache project-scoped discovery in `Context` when several tasks need it; -the underlying API should also accept the discovered state directly. +- Use typed parameters. Required scalars are positional by default; defaults, `Option`, and `Vec` produce named options. Use `#[bake(named)]` for a required named option. A `Vec` can opt into positional variadic arguments with `#[bake(positional)]`; it must be the last positional parameter, and callers must use `::` before a following task. Document arguments with `help`. +- Resolve project-relative paths against `context.root()`. Use `context.command(...)` for project subprocesses, or pass an explicit working directory to an operation acting on another checkout. Avoid changing the process-wide working directory or environment. +- Validate inputs before making changes. Include the affected file, package, or command in errors when that context helps identify the failure. Propagate failures from operations and hooks. +- Return the semantic result. Text is appropriate for release notes; a list or serializable result struct suits package metadata or an update summary. Use `()` when there is no useful result. Avoid making callers parse a success message to recover counts, paths, or other structured data. Existing output shapes also need compatibility consideration when migrating a library. +- Let Bake's `output` task format the final result. Send progress and diagnostics to stderr. Use `#[bake::task(output)]` only when the task owns its final output; subprocess progress alone does not require it. + +Use ordinary Rust calls to compose implementation operations. Use `context.call(...)` where composition is intentionally through registered tasks, including project-defined hooks. Use `call_if_registered` for optional hooks and document when they run and which arguments they receive. Libraries can cache project-scoped discovery in `Context` when several tasks need it; the underlying API should also accept the discovered state directly. ## Consume task libraries -Add a reusable task library as a dependency of the local task binary, then run -`cargo bake --regenerate` so its registration entries are linked: +Add a reusable task library as a dependency of the local task binary, then run `cargo bake --regenerate` so its registration entries are linked: ```toml [dependencies] -bake = "0.18" +bake = "0.19" socketry_executor = { package = "socketry-executor", version = "0.1" } -bake_agent_context = "0.1" +bake_agent_context = "0.3" ``` -The first `cargo bake --regenerate` creates the private `bake/` workspace member -and its minimal binary if they do not exist. Each run regenerates a small source -file that links unconditional, non-optional, platform-independent direct -dependencies in `bake/Cargo.toml` (apart from `bake` itself), and adds a module -declaration to the selected binary if needed. It preserves the rest of the task -source. Put reusable task libraries in `[dependencies]`; ordinary dependencies -used by task code are also linked. - -No per-task imports or registration calls are needed. The task attributes and -defining modules determine command names. `Registry::discover()` reports an -error if two linked crates register the same task name. A crate used only as a -normal Rust dependency does not need to expose a Bake executable; Cargo does -not run a dependency's binary target when building your application. - -The `bake-agent-context` task library provides dependency context discovery and -installation in the same executable. Run `cargo bake agent:context:install` -to install guidance from resolved dependencies. Follow that package's context -for the generated index, skills, and repository-owned agent instructions. - -If ordinary users of a library should not inherit its Bake dependency, put the -tasks in a separate companion crate, such as `socketry-executor-bake`. The -project's task binary then depends on and references that companion crate instead. -This keeps the main library's dependencies smaller, at the cost of one extra -package dependency for projects that want its tasks. +The first `cargo bake --regenerate` creates the private `bake/` workspace member and its minimal binary if they do not exist. Each run regenerates a small source file that links unconditional, non-optional, platform-independent direct dependencies in `bake/Cargo.toml` (apart from `bake` itself), and adds a module declaration to the selected binary if needed. It preserves the rest of the task source. Put reusable task libraries in `[dependencies]`; ordinary dependencies used by task code are also linked. + +No per-task imports or registration calls are needed. The task attributes and defining modules determine command names. `Registry::discover()` reports an error if two linked crates register the same task name. A crate used only as a normal Rust dependency does not need to expose a Bake executable; Cargo does not run a dependency's binary target when building your application. + +The `bake-agent-context` task library provides dependency context discovery and installation in the same executable. Run `cargo bake agent:context:install` to install guidance from resolved dependencies. Follow that package's context for the generated index, skills, and repository-owned agent instructions. + +If ordinary users of a library should not inherit its Bake dependency, put the tasks in a separate companion crate, such as `socketry-executor-bake`. The project's task binary then depends on and references that companion crate instead. This keeps the main library's dependencies smaller, at the cost of one extra package dependency for projects that want its tasks. ## Use shared project composition -In Socketry repositories, depend on `socketry-project` in the private `bake/` -package to obtain the standard development tasks and release hook. Its -`cargo:after_version_bump` hook composes license, release-note, and readme -updates. Keep this composition in the shared project crate, and keep the local -executable focused on project-specific additions. A reusable task library -should not depend on `socketry-project` merely to obtain its own development -tooling. +In Socketry repositories, depend on `socketry-project` in the private `bake/` package to obtain the standard development tasks and release hook. Its `cargo:after_version_bump` hook composes license, release-note, and readme updates. Keep this composition in the shared project crate, and keep the local executable focused on project-specific additions. A reusable task library should not depend on `socketry-project` merely to obtain its own development tooling. -During development of a task library, ensure the private executable resolves -that library to the current checkout, including when it arrives transitively -through `socketry-project`. For example, the root workspace manifest of -`bake-releases` can contain: +During development of a task library, ensure the private executable resolves that library to the current checkout, including when it arrives transitively through `socketry-project`. For example, the root workspace manifest of `bake-releases` can contain: ```toml [patch.crates-io] bake-releases = { path = "." } ``` -The local package version must satisfy the dependency requirements. Inspect -Cargo's resolved dependency graph; adding a direct path dependency alone can -leave a second registry copy linked through another dependency. Refresh the -lockfile when resolution changes, and regenerate task links when dependencies -of the private executable change. +The local package version must satisfy the dependency requirements. Inspect Cargo's resolved dependency graph; adding a direct path dependency alone can leave a second registry copy linked through another dependency. Refresh the lockfile when resolution changes, and regenerate task links when dependencies of the private executable change. ## Align an existing library -Start by identifying the public Rust operations, registered command names, -arguments, results, and hook behavior. Preserve those contracts while moving -implementation into semantic modules and adding root re-exports. Keep existing -Rust import paths as compatibility re-exports when needed, and document any -intentional breaking API or output change. - -Review unnamed tasks in `bake_*` libraries when adopting crate-derived -namespaces. Tasks at the crate root gain a prefix, and tasks under a different -domain gain the crate prefix as well. For example, the default name for -`bake_cargo::releases::github::release` is `cargo:releases:github:release`. -Call that full name in workflows and task chains; the short -`releases:github:release` compatibility alias was removed in Bake Cargo 0.3.0. -The standard publishing workflow also uses `cargo:release:detect`, -`cargo:publish:pending`, and `cargo:release:publish` for the release lifecycle. -Use explicit names to preserve existing command contracts where needed. -Existing module paths that already start with the crate's domain are unchanged. - -Generated descriptors now carry their complete names before registration, -including module namespaces for libraries without a `bake_` prefix and for -explicit short names. Review manual registries that previously added those -namespaces using `Registry::include`: it still prepends the supplied namespace, -so importing an already namespaced descriptor can repeat that prefix. Register -the descriptor directly when its inferred name is the intended command. - -Then align the task adapters, local dependency resolution, and tests with this -guide. Reuse Socketry's layout and testing guidance, and record domain-specific -exceptions in the library's own context. Apply the conventions as each library -is reviewed; the illustrative APIs above do not imply that all current task -libraries have already adopted them. +Start by identifying the public Rust operations, registered command names, arguments, results, and hook behavior. Preserve those contracts while moving implementation into semantic modules and adding root re-exports. Keep existing Rust import paths as compatibility re-exports when needed, and document any intentional breaking API or output change. + +Review unnamed tasks in `bake_*` libraries when adopting crate-derived namespaces. Tasks at the crate root gain a prefix, and tasks under a different domain gain the crate prefix as well. For example, the default name for `bake_cargo::releases::github::release` is `cargo:releases:github:release`. Call that full name in workflows and task chains; the short `releases:github:release` compatibility alias was removed in Bake Cargo 0.3.0. The standard publishing workflow also uses `cargo:release:detect`, `cargo:publish:pending`, and `cargo:release:publish` for the release lifecycle. Use explicit names to preserve existing command contracts where needed. Existing module paths that already start with the crate's domain are unchanged. + +Generated descriptors now carry their complete names before registration, including module namespaces for libraries without a `bake_` prefix and for explicit short names. Review manual registries that previously added those namespaces using `Registry::include`: it still prepends the supplied namespace, so importing an already namespaced descriptor can repeat that prefix. Register the descriptor directly when its inferred name is the intended command. + +Then align the task adapters, local dependency resolution, and tests with this guide. Reuse Socketry's layout and testing guidance, and record domain-specific exceptions in the library's own context. Apply the conventions as each library is reviewed; the illustrative APIs above do not imply that all current task libraries have already adopted them. diff --git a/context/testing-task-libraries.md b/context/testing-task-libraries.md index aa12089..2a13eda 100644 --- a/context/testing-task-libraries.md +++ b/context/testing-task-libraries.md @@ -1,35 +1,18 @@ # Testing Task Libraries -Verify a task library's semantic Rust API, registered Bake interface, and -executable composition at their respective boundaries. +Verify a task library's semantic Rust API, registered Bake interface, and executable composition at their respective boundaries. -Follow [Structuring Bake Tasks in Crates](task-libraries.md) for implementation -and command naming. Socketry's -[layout guide](https://github.com/socketry/socketry-project-rust/blob/main/context/layout.md) -defines where unit and integration tests belong, and its -[testing guidance](https://github.com/socketry/socketry-project-rust/blob/main/context/testing.md) -defines coverage expectations. Use the `bake-test-rust` context for the shared -test commands and CI workflows. +Follow [Structuring Bake Tasks in Crates](task-libraries.md) for implementation and command naming. Socketry's [layout guide](https://github.com/socketry/socketry-project-rust/blob/main/context/layout.md) defines where unit and integration tests belong, and its [testing guidance](https://github.com/socketry/socketry-project-rust/blob/main/context/testing.md) defines coverage expectations. Use the `bake-test-rust` context for the shared test commands and CI workflows. ## Test semantic operations -Exercise parsing, transformations, discovery, and updates through the ordinary -Rust interface. Use public API integration tests for caller-visible behavior -and module-local tests where private implementation details need verification. -Keep substantial implementation suites with the library that owns them. +Exercise parsing, transformations, discovery, and updates through the ordinary Rust interface. Use public API integration tests for caller-visible behavior and module-local tests where private implementation details need verification. Keep substantial implementation suites with the library that owns them. -Cover meaningful failure behavior as well as successful results. For file -updates, this can include preservation of unrelated content, repeated updates, -and the state left after a failed write. For publishing or subprocess tasks, -check which operations happened before a failure and whether later operations -were skipped. Test these properties where the implementation owns them. +Cover meaningful failure behavior as well as successful results. For file updates, this can include preservation of unrelated content, repeated updates, and the state left after a failed write. For publishing or subprocess tasks, check which operations happened before a failure and whether later operations were skipped. Test these properties where the implementation owns them. ## Test registered task contracts -Calling an annotated Rust function directly does not exercise discovery or -generated argument conversion. Add integration tests in the library's `tests/` -directory that link the library, discover its tasks, and invoke them by their -public command names. For example, a release-task test can use: +Calling an annotated Rust function directly does not exercise discovery or generated argument conversion. Add integration tests in the library's `tests/` directory that link the library, discover its tasks, and invoke them by their public command names. For example, a release-task test can use: ```rust,ignore use bake_releases as _; @@ -51,64 +34,28 @@ fn reads_release_notes_from_the_context_root() { } ``` -Check each library's registered names and relevant defaults, required and -optional arguments, project-root behavior, result values, and propagated -errors. Select representative cases for each adapter; keep the full domain -case matrix with the operation tests. Bake itself owns exhaustive tests of its -generic argument parser and formatter. +Check each library's registered names and relevant defaults, required and optional arguments, project-root behavior, result values, and propagated errors. Select representative cases for each adapter; keep the full domain case matrix with the operation tests. Bake itself owns exhaustive tests of its generic argument parser and formatter. -If a library exposes generated descriptors for manual registration, check that -their names and invocation behavior agree with automatic discovery. Descriptors -already contain the complete name resolved during compilation. +If a library exposes generated descriptors for manual registration, check that their names and invocation behavior agree with automatic discovery. Descriptors already contain the complete name resolved during compilation. -For hooks, use a fresh `Registry` and context state to record calls and their -arguments. Assert invocation order, optional-hook absence, and error propagation -where these are part of the contract. Register or replace small recording -handlers instead of running unrelated release or publishing operations. Keep -tests of a shared hook's full behavior in the crate that provides that hook. +For hooks, use a fresh `Registry` and context state to record calls and their arguments. Assert invocation order, optional-hook absence, and error propagation where these are part of the contract. Register or replace small recording handlers instead of running unrelated release or publishing operations. Keep tests of a shared hook's full behavior in the crate that provides that hook. ## Test executable composition -Keep a small suite under `bake/tests/` that launches the private executable -using `CARGO_BIN_EXE_`. Verify task discovery through `--list`, plus -representative command execution, stdout/stderr, and success/failure exit -status. A registry-level test complements these checks but does not exercise -the process entry point. +Keep a small suite under `bake/tests/` that launches the private executable using `CARGO_BIN_EXE_`. Verify task discovery through `--list`, plus representative command execution, stdout/stderr, and success/failure exit status. A registry-level test complements these checks but does not exercise the process entry point. -Ensure these tests link the task library from the current checkout. Check the -resolved dependency graph for a registry copy of the package under development, -especially when `socketry-project` supplies tasks transitively. Testing a -published copy does not verify local changes to registration or adapters. +Ensure these tests link the task library from the current checkout. Check the resolved dependency graph for a registry copy of the package under development, especially when `socketry-project` supplies tasks transitively. Testing a published copy does not verify local changes to registration or adapters. -Keep the private binary small. Its tests establish that the selected libraries -compose correctly; the reusable libraries own their detailed behavior tests. +Keep the private binary small. Its tests establish that the selected libraries compose correctly; the reusable libraries own their detailed behavior tests. ## Keep fixtures isolated and purposeful -Use `tempfile::TempDir` for owned temporary projects and RAII cleanup. Share -fixture builders within a test suite when they express useful operations such -as creating a Cargo workspace or committing a Git revision. Prefer these -established facilities over custom timestamp-based temporary directories. - -Configure working directories and environment variables on child `Command` -instances. For in-process operation tests, pass executable paths, clients, or -other collaborators explicitly where the operation needs them. Avoid mutating -the test process's environment to select a fake tool. A mutex used by some tests -does not isolate those changes from other code running in the same process. - -Use local Git repositories, fake executables, and local HTTP servers when the -behavior crosses those boundaries. Record arguments and control results so -tests can inspect success, failure, and partial completion without contacting -live publishing services. Gate platform-specific fixtures explicitly and retain -portable tests for the shared contract. - -Introduce failure injection at a narrow boundary where real error handling -needs verification. Keep ordinary and coverage builds behaviorally aligned; -avoid exposing public coverage-only APIs or reproducing a library's private -failure tests in its development executable just to satisfy instrumentation. -Review both the uncovered behavior and the coverage configuration when results -differ between builds. - -Start with suite-local support modules. Extract shared fixture code across -crates when the repeated behavior has a clear common contract; each library -can retain fixtures specific to its domain. +Use `tempfile::TempDir` for owned temporary projects and RAII cleanup. Share fixture builders within a test suite when they express useful operations such as creating a Cargo workspace or committing a Git revision. Prefer these established facilities over custom timestamp-based temporary directories. + +Configure working directories and environment variables on child `Command` instances. For in-process operation tests, pass executable paths, clients, or other collaborators explicitly where the operation needs them. Avoid mutating the test process's environment to select a fake tool. A mutex used by some tests does not isolate those changes from other code running in the same process. + +Use local Git repositories, fake executables, and local HTTP servers when the behavior crosses those boundaries. Record arguments and control results so tests can inspect success, failure, and partial completion without contacting live publishing services. Gate platform-specific fixtures explicitly and retain portable tests for the shared contract. + +Introduce failure injection at a narrow boundary where real error handling needs verification. Keep ordinary and coverage builds behaviorally aligned; avoid exposing public coverage-only APIs or reproducing a library's private failure tests in its development executable just to satisfy instrumentation. Review both the uncovered behavior and the coverage configuration when results differ between builds. + +Start with suite-local support modules. Extract shared fixture code across crates when the repeated behavior has a clear common contract; each library can retain fixtures specific to its domain. diff --git a/license.md b/license.md index e589fcc..17fbb94 100644 --- a/license.md +++ b/license.md @@ -1,21 +1,9 @@ # MIT License -Copyright, 2026, by Samuel Williams. +Copyright, 2026, by Samuel Williams. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/readme.md b/readme.md index 9b17df4..de484d4 100644 --- a/readme.md +++ b/readme.md @@ -1,17 +1,12 @@ # `bake` -Write project tasks as ordinary Rust functions, then run them with `cargo bake`. -Task functions have typed arguments, generated help, automatic discovery, and a -shared project context. Reusable task libraries are ordinary Cargo dependencies. +Write project tasks as ordinary Rust functions, then run them with `cargo bake`. Task functions have typed arguments, generated help, automatic discovery, and a shared project context. Reusable task libraries are ordinary Cargo dependencies. -This is an initial implementation inspired by [Ruby Bake](https://github.com/ioquatix/bake), -[Bake Releases](https://github.com/ioquatix/bake-releases), and Cargo's -[xtask pattern](https://github.com/matklad/cargo-xtask). +This is an initial implementation inspired by [Ruby Bake](https://github.com/ioquatix/bake), [Bake Releases](https://github.com/ioquatix/bake-releases), and Cargo's [xtask pattern](https://github.com/matklad/cargo-xtask). ## Try this repository -Install the `socketry-cargo-bake` launcher from this checkout, then run the -project tasks: +Install the `socketry-cargo-bake` launcher from this checkout, then run the project tasks: ```sh cargo install --path crates/cargo-bake --locked @@ -24,19 +19,15 @@ cargo bake cargo:packages cargo bake license:update ``` -The task crate is [bake/](bake/src/main.rs). Cargo compiles it on demand and caches -the build. `--offline` and `--locked` are available before the task name. +The task crate is [bake/](bake/src/main.rs). Cargo compiles it on demand and caches the build. `--offline` and `--locked` are available before the task name. -The executable is `cargo-bake`; Cargo makes it available as `cargo bake`. -The core library package is `bake`, and the launcher package is -`socketry-cargo-bake`. To install the published launcher: +The executable is `cargo-bake`; Cargo makes it available as `cargo bake`. The core library package is `bake`, and the launcher package is `socketry-cargo-bake`. To install the published launcher: ```sh cargo install socketry-cargo-bake ``` -The earlier `socketry-bake` package remains available for existing projects; use -`bake` for new projects. +The earlier `socketry-bake` package remains available for existing projects; use `bake` for new projects. ## Add tasks to a project @@ -67,7 +58,7 @@ edition = "2024" publish = false [dependencies] -bake = "0.18" +bake = "0.19" ``` In `bake/src/main.rs`: @@ -86,16 +77,7 @@ fn main() -> Result<()> { } ``` -`#[bake::task]` preserves `greet` and generates `greet_task()`, which describes -the arguments and adapts command-line input to the original function. It also adds -the descriptor to Bake's link-time registration table. `Registry::discover()` -collects tasks from the executable and linked task libraries. Nested Rust modules -form namespaces by default. Library crate names beginning with `bake_` supply -a prefix too: `bake_releases::notes` registers as `releases:notes`. A fully -qualified name such as `#[bake::task(name = "releases:notes")]` overrides -inference. Project binary targets keep their existing module-based names. -Names are resolved at compile time, so generated descriptors contain the same -final names whether registered manually or collected by `Registry::discover()`. +`#[bake::task]` preserves `greet` and generates `greet_task()`, which describes the arguments and adapts command-line input to the original function. It also adds the descriptor to Bake's link-time registration table. `Registry::discover()` collects tasks from the executable and linked task libraries. Nested Rust modules form namespaces by default. Library crate names beginning with `bake_` supply a prefix too: `bake_releases::notes` registers as `releases:notes`. A fully qualified name such as `#[bake::task(name = "releases:notes")]` overrides inference. Project binary targets keep their existing module-based names. Names are resolved at compile time, so generated descriptors contain the same final names whether registered manually or collected by `Registry::discover()`. ## Arguments and results @@ -112,64 +94,36 @@ final names whether registered manually or collected by `Registry::discover()`. | `context: &mut Context` | Injected execution context, omitted from command-line arguments | | `#[bake(input)] input: Value` | Injected result from the preceding task in a chain | -Values implement `FromStr`, with a displayable error. Custom argument types can -implement that trait. Defaults other than string literals must produce the -parameter's type. Defaults are evaluated when invoking the task. Parameter help -comes from `#[bake(help = "...")]`; task help comes from Rust documentation comments. -An explicitly marked `#[bake(context)]` parameter may have another name. +Values implement `FromStr`, with a displayable error. Custom argument types can implement that trait. Defaults other than string literals must produce the parameter's type. Defaults are evaluated when invoking the task. Parameter help comes from `#[bake(help = "...")]`; task help comes from Rust documentation comments. An explicitly marked `#[bake(context)]` parameter may have another name. -Named arguments use two tokens: `--name value`. This also applies to boolean and -repeatable arguments. Equals signs are not a named-argument separator; flag names -accept hyphens in place of underscores. Use `--` before positional values that -look like options. `::` is reserved as a task separator. UTF-8 task arguments are -required. +Named arguments use two tokens: `--name value`. This also applies to boolean and repeatable arguments. Equals signs are not a named-argument separator; flag names accept hyphens in place of underscores. Use `--` before positional values that look like options. `::` is reserved as a task separator. UTF-8 task arguments are required. -By default, `Vec` parameters are repeatable named options. Add -`#[bake(positional)]` to make a `Vec` consume bare positional values instead. -It must be the last positional parameter in its task. Since it cannot infer -where a following task starts, use `::` before another task: +By default, `Vec` parameters are repeatable named options. Add `#[bake(positional)]` to make a `Vec` consume bare positional values instead. It must be the last positional parameter in its task. Since it cannot infer where a following task starts, use `::` before another task: ```sh cargo bake files:normalize path/one.md path/two.md :: output ``` -Task functions return `Result` where `Output` implements -`serde::Serialize` and the error implements `Display`. `bake::Result` is a -convenience alias. After the final task, Bake invokes its registered `output` -task unless that task handled output itself. The default `output` task prints -strings as text, structured values as pretty JSON, and `()` silently. A leading -`--json` selects JSON, including for strings and null. Tasks should use stderr -for diagnostics when callers need machine-readable stdout. +Task functions return `Result` where `Output` implements `serde::Serialize` and the error implements `Display`. `bake::Result` is a convenience alias. After the final task, Bake invokes its registered `output` task unless that task handled output itself. The default `output` task prints strings as text, structured values as pretty JSON, and `()` silently. A leading `--json` selects JSON, including for strings and null. Tasks should use stderr for diagnostics when callers need machine-readable stdout. -The built-in `output` task also works in a chain. Its input is the previous -task's result, and it returns that result for further processing: +The built-in `output` task also works in a chain. Its input is the previous task's result, and it returns that result for further processing: ```sh cargo bake greet Samuel output --format json cargo bake releases:notes Unreleased output --file notes.txt ``` -Use `--format raw`, `--format json`, or `--format ndjson`; JSON and NDJSON file -extensions also select a format. Raw text is the default for other file extensions. -Output files are relative to the project root, and their parent directories must exist. -The `null` task consumes a result without printing it. Mark a custom task with -`#[bake::task(output)]` if it handles output, or replace the default formatter -with `registry.replace("output", custom_output_task())`. +Use `--format raw`, `--format json`, or `--format ndjson`; JSON and NDJSON file extensions also select a format. Raw text is the default for other file extensions. Output files are relative to the project root, and their parent directories must exist. The `null` task consumes a result without printing it. Mark a custom task with `#[bake::task(output)]` if it handles output, or replace the default formatter with `registry.replace("output", custom_output_task())`. ## Composition and hooks -Chain tasks with `::`. Bare task names also start a new task once the preceding -task's positional arguments are filled. An unbounded positional `Vec` consumes -all bare arguments through the end of its invocation, so an explicit `::` is -required before another task. Explicit separators make intent clearer: +Chain tasks with `::`. Bare task names also start a new task once the preceding task's positional arguments are filled. An unbounded positional `Vec` consumes all bare arguments through the end of its invocation, so an explicit `::` is required before another task. Explicit separators make intent clearer: ```sh cargo bake add 20 22 :: result ``` -The entire chain is parsed and supplied values are type-checked before the first -task runs. Execution stops at the first error. Validation calls `FromStr` before -the adapter converts values again; argument parsers should be free of side effects. +The entire chain is parsed and supplied values are type-checked before the first task runs. Execution stops at the first error. Validation calls `FromStr` before the adapter converts values again; argument parsers should be free of side effects. Each invocation receives the same `Context`. It provides: @@ -177,26 +131,16 @@ Each invocation receives the same `Context`. It provides: - `previous()` — the previous successful task's structured result. - `insert`, `get`, `get_mut` — shared state indexed by Rust type. - `call("task:name", &["--argument", "value"])` — invoke one task by its full registered name. -- `call_if_registered("task:name", &[...])` — invoke an optional task, - returning `None` if it is not registered. +- `call_if_registered("task:name", &[...])` — invoke an optional task, returning `None` if it is not registered. - `command("cargo")` — a `std::process::Command` configured to run in the project root. -Hooks are ordinary calls around an operation. For example, this repository's -`release:prepare` task calls `build:check`, then `releases:notes`. Direct Rust -function calls are also available when registry dispatch is unnecessary; they -do not automatically update `previous()`. +Hooks are ordinary calls around an operation. For example, this repository's `release:prepare` task calls `build:check`, then `releases:notes`. Direct Rust function calls are also available when registry dispatch is unnecessary; they do not automatically update `previous()`. -Reusable tasks can invoke project-local hooks through the shared registry. The -`bake-cargo` version tasks optionally call `cargo:after_version_bump`, passing -the new workspace version. A project can define that task in its private -`bake/` crate; if it is absent, the version bump continues without a hook. +Reusable tasks can invoke project-local hooks through the shared registry. The `bake-cargo` version tasks optionally call `cargo:after_version_bump`, passing the new workspace version. A project can define that task in its private `bake/` crate; if it is absent, the version bump continues without a hook. ## Reusable task libraries -Give the library a semantic Rust API, then expose its operations with the task -attribute. Small adapters can resolve project-relative paths and translate -command arguments. For example, a `bake_releases` library with a `read_notes` -operation could expose a task directly from its crate root: +Give the library a semantic Rust API, then expose its operations with the task attribute. Small adapters can resolve project-relative paths and translate command arguments. For example, a `bake_releases` library with a `read_notes` operation could expose a task directly from its crate root: ```rust,ignore // src/lib.rs @@ -210,23 +154,11 @@ pub fn notes( } ``` -Keep the main Rust API accessible at the crate root, with modules for meaningful -domain concepts. This function would be called as `bake_releases::notes` in -Rust and `releases:notes` through Bake. Bake removes the leading `bake_` and -converts remaining crate-name underscores to colons, so `bake_agent_context` -supplies `agent:context`. Nested modules extend that namespace, with module-name -underscores converted to hyphens. A matching namespace already expressed by -wrapper modules is included only once. An operation whose signature already -suits Bake can be annotated directly. +Keep the main Rust API accessible at the crate root, with modules for meaningful domain concepts. This function would be called as `bake_releases::notes` in Rust and `releases:notes` through Bake. Bake removes the leading `bake_` and converts remaining crate-name underscores to colons, so `bake_agent_context` supplies `agent:context`. Nested modules extend that namespace, with module-name underscores converted to hyphens. A matching namespace already expressed by wrapper modules is included only once. An operation whose signature already suits Bake can be annotated directly. -Explicit names retain their existing behavior: `name = "namespace:task"` -specifies the entire name, while a short name uses only the defining module's -namespace. This lets libraries preserve names such as a root `test` command. -See the [migration guidance](context/task-libraries.md#align-an-existing-library) -for existing library tasks whose default names gain a crate prefix. +Explicit names retain their existing behavior: `name = "namespace:task"` specifies the entire name, while a short name uses only the defining module's namespace. This lets libraries preserve names such as a root `test` command. See the [migration guidance](context/task-libraries.md#align-an-existing-library) for existing library tasks whose default names gain a crate prefix. -Add the library as a Cargo dependency and reference it from the task binary so -Rust includes its registration entries in the link: +Add the library as a Cargo dependency and reference it from the task binary so Rust includes its registration entries in the link: ```rust,ignore use bake_releases as _; @@ -234,10 +166,7 @@ use bake_releases as _; bake::Registry::discover()?.run() ``` -This removes per-task registration and namespace boilerplate. Explicit -`Registry::register` and `Registry::include` remain available when a project needs -to assemble names dynamically. Duplicate discovered names are errors. The -[Bake Releases](https://github.com/socketry/bake-releases-rust) library provides: +This removes per-task registration and namespace boilerplate. Explicit `Registry::register` and `Registry::include` remain available when a project needs to assemble names dynamically. Duplicate discovered names are errors. The [Bake Releases](https://github.com/socketry/bake-releases-rust) library provides: ```sh cargo bake releases:notes Unreleased @@ -245,55 +174,28 @@ cargo bake releases:update v0.1.0 cargo bake releases:notes v0.1.0 --path releases.md ``` -`update` renames the `Unreleased` heading in the file. It does not change package -versions, commit, tag, or publish. Release headings use the documented ATX format -such as `## v0.1.0`. - -The companion [Bake Cargo](https://github.com/socketry/bake-cargo-rust) library -provides Cargo workspace tasks, GitHub release creation, publishing workflow -generation, GitHub release protections, and crates.io trusted publishers. Its -shared version tasks optionally invoke `cargo:after_version_bump` with the new -version. Socketry projects use `socketry-project` in their private task package -to supply the shared hook for license, release-note, and readme updates. -`cargo:release` validates and packages a candidate for a -reviewed release pull request. After the pull request merges, the workflow waits -for the `crates-io` environment approval, publishes the workspace through -trusted publishing, and creates the `vVERSION` tag after all uploads succeed. -The initial publish can be followed by -trusted-publisher setup with the explicit `cargo:bootstrap PACKAGE` task. Review -its effects and package contents before invoking it. - -The separately reusable [Bake License](https://github.com/socketry/bake-license-rust) -library tracks Git authorship, refreshes `license.md`, removes the README License -section, and updates Rust source copyright headers. - -See the [task library guide](context/task-libraries.md) for more details on -structuring and using reusable task libraries. +`update` renames the `Unreleased` heading in the file. It does not change package versions, commit, tag, or publish. Release headings use the documented ATX format such as `## v0.1.0`. + +The companion [Bake Cargo](https://github.com/socketry/bake-cargo-rust) library provides Cargo workspace tasks, GitHub release creation, publishing workflow generation, GitHub release protections, and crates.io trusted publishers. Its shared version tasks optionally invoke `cargo:after_version_bump` with the new version. Socketry projects use `socketry-project` in their private task package to supply the shared hook for license, release-note, and readme updates. `cargo:release` validates and packages a candidate for a reviewed release pull request. After the pull request merges, the workflow waits for the `crates-io` environment approval, publishes the workspace through trusted publishing, and creates the `vVERSION` tag after all uploads succeed. The initial publish can be followed by trusted-publisher setup with the explicit `cargo:bootstrap PACKAGE` task. Review its effects and package contents before invoking it. + +The separately reusable [Bake License](https://github.com/socketry/bake-license-rust) library tracks Git authorship, refreshes `license.md`, removes the README License section, and updates Rust source copyright headers. + +See the [task library guide](context/task-libraries.md) for more details on structuring and using reusable task libraries. ## Discovery and configuration -The launcher uses `cargo metadata --format-version 1 --no-deps`. From a workspace -member it defaults to the workspace's `bake/Cargo.toml`. Override the path with: +The launcher uses `cargo metadata --format-version 1 --no-deps`. From a workspace member it defaults to the workspace's `bake/Cargo.toml`. Override the path with: ```toml [workspace.metadata.bake] manifest = "development/Cargo.toml" ``` -`[package.metadata.bake]` takes precedence for the selected package; its path and -execution root are relative to that package. Workspace configuration is relative -to the workspace root. `--manifest-path PATH` selects the **project** manifest. -Options that take values use a separate following argument. +`[package.metadata.bake]` takes precedence for the selected package; its path and execution root are relative to that package. Workspace configuration is relative to the workspace root. `--manifest-path PATH` selects the **project** manifest. Options that take values use a separate following argument. -The task package must have one binary, or select it with `package.default-run`. -It can belong to the project workspace, or be a separate workspace excluded from -the parent. A separate task workspace has its own dependency resolution and lockfile. +The task package must have one binary, or select it with `package.default-run`. It can belong to the project workspace, or be a separate workspace excluded from the parent. A separate task workspace has its own dependency resolution and lockfile. -Launcher options (`--manifest-path PATH`, `--offline`, `--locked`, `--release`) go -before the task name. Everything from the first task argument onward is forwarded intact. -`cargo bake --help` explains the launcher without compiling tasks; `--list` and -`TASK --help` compile and query the project's task registry. Child exit codes -are preserved. Process arguments are passed directly, without a shell. +Launcher options (`--manifest-path PATH`, `--offline`, `--locked`, `--release`) go before the task name. Everything from the first task argument onward is forwarded intact. `cargo bake --help` explains the launcher without compiling tasks; `--list` and `TASK --help` compile and query the project's task registry. Child exit codes are preserved. Process arguments are passed directly, without a shell. ## Packages @@ -307,52 +209,41 @@ are preserved. Process arguments are passed directly, without a shell. | `bake-license` | `bake_license` | License and copyright maintenance tasks ([repository](https://github.com/socketry/bake-license-rust)) | | `bake-agent-context` | `bake_agent_context` | Dependency context tasks ([repository](https://github.com/socketry/bake-agent-context-rust)) | -For local development of the task binary, check out the task repositories beside -this repository as `../bake-releases-rust`, `../bake-cargo-rust`, and -`../bake-license-rust`. +For local development of the task binary, check out the task repositories beside this repository as `../bake-releases-rust`, `../bake-cargo-rust`, and `../bake-license-rust`. -Tasks are synchronous in this initial implementation. An individual task can -start a runtime or a subprocess; Bake imposes no async runtime dependency. +Tasks are synchronous in this initial implementation. An individual task can start a runtime or a subprocess; Bake imposes no async runtime dependency. ## 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. Follow the shared -[Releasing skill](https://github.com/socketry/socketry-project-rust/blob/main/context/releasing.md) -for the standard process. +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. Follow the shared [Releasing skill](https://github.com/socketry/socketry-project-rust/blob/main/context/releasing.md) for the standard process. ## Releases + See [releases.md](releases.md) for the full release history. +### v0.19.1 + +- Keep generated dependency skills out of the tracked repository. + +- Adopt `socketry-project` 0.3.7 for shared project tasks and Markdown normalization. + +- Require the aggregate test and coverage result for pull request merges. + +- Refresh dependency examples and repository-owned agent guidance. + ### v0.19.0 -- Support unbounded positional `Vec` task arguments with - `#[bake(positional)]`. Require `::` before chaining another task. +- Support unbounded positional `Vec` task arguments with `#[bake(positional)]`. Require `::` before chaining another task. ### v0.18.0 -- Derive default task namespaces from `bake_*` library crate names, stripping - `bake_` and translating remaining underscores to colons. Preserve explicit - names, project binary names, and matching module prefixes. Existing unnamed - library tasks outside those prefixes gain a namespace; use explicit names to - retain their previous commands. -- Use `bake = "0"` for reusable task libraries so linked crates resolve one - Bake 0.x version and share its task registry. -- Resolve task names at compile time. Generated descriptors now include their - full namespaces, making manual registration and automatic discovery agree. - Manual registries that added those namespaces with `Registry::include` should - register the descriptors directly to avoid repeating the prefix. -- Document semantic task-library APIs, crate-derived namespaces, and testing - conventions aligned with `socketry-project`. - -### v0.17.4 - -- Use the shared `socketry-project` Releasing skill for the standard release - process and remove references to the duplicate Bake Cargo publishing context. +- Derive default task namespaces from `bake_*` library crate names, stripping `bake_` and translating remaining underscores to colons. Preserve explicit names, project binary names, and matching module prefixes. Existing unnamed library tasks outside those prefixes gain a namespace; use explicit names to retain their previous commands. +- Use `bake = "0"` for reusable task libraries so linked crates resolve one Bake 0.x version and share its task registry. +- Resolve task names at compile time. Generated descriptors now include their full namespaces, making manual registration and automatic discovery agree. Manual registries that added those namespaces with `Registry::include` should register the descriptors directly to avoid repeating the prefix. +- Document semantic task-library APIs, crate-derived namespaces, and testing conventions aligned with `socketry-project`. + ## Contributing @@ -361,4 +252,4 @@ Please open an issue or pull request on [GitHub](https://github.com/socketry/bak ### 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. +Run `cargo bake agent:context:install` to install shared context and skills. Read `.agents/context/index.md` to find relevant guides, follow `agents.md` if present, and apply skills under `.agents/skills/`. The installer preserves repository-owned `agents.md`; it does not create or regenerate that file. diff --git a/releases.md b/releases.md index ecdba30..ec18db9 100644 --- a/releases.md +++ b/releases.md @@ -1,36 +1,34 @@ # Releases +## v0.19.1 + +- Keep generated dependency skills out of the tracked repository. + +- Adopt `socketry-project` 0.3.7 for shared project tasks and Markdown normalization. + +- Require the aggregate test and coverage result for pull request merges. + +- Refresh dependency examples and repository-owned agent guidance. + ## v0.19.0 -- Support unbounded positional `Vec` task arguments with - `#[bake(positional)]`. Require `::` before chaining another task. +- Support unbounded positional `Vec` task arguments with `#[bake(positional)]`. Require `::` before chaining another task. ## v0.18.0 -- Derive default task namespaces from `bake_*` library crate names, stripping - `bake_` and translating remaining underscores to colons. Preserve explicit - names, project binary names, and matching module prefixes. Existing unnamed - library tasks outside those prefixes gain a namespace; use explicit names to - retain their previous commands. -- Use `bake = "0"` for reusable task libraries so linked crates resolve one - Bake 0.x version and share its task registry. -- Resolve task names at compile time. Generated descriptors now include their - full namespaces, making manual registration and automatic discovery agree. - Manual registries that added those namespaces with `Registry::include` should - register the descriptors directly to avoid repeating the prefix. -- Document semantic task-library APIs, crate-derived namespaces, and testing - conventions aligned with `socketry-project`. +- Derive default task namespaces from `bake_*` library crate names, stripping `bake_` and translating remaining underscores to colons. Preserve explicit names, project binary names, and matching module prefixes. Existing unnamed library tasks outside those prefixes gain a namespace; use explicit names to retain their previous commands. +- Use `bake = "0"` for reusable task libraries so linked crates resolve one Bake 0.x version and share its task registry. +- Resolve task names at compile time. Generated descriptors now include their full namespaces, making manual registration and automatic discovery agree. Manual registries that added those namespaces with `Registry::include` should register the descriptors directly to avoid repeating the prefix. +- Document semantic task-library APIs, crate-derived namespaces, and testing conventions aligned with `socketry-project`. ## v0.17.4 -- Use the shared `socketry-project` Releasing skill for the standard release - process and remove references to the duplicate Bake Cargo publishing context. +- Use the shared `socketry-project` Releasing skill for the standard release process and remove references to the duplicate Bake Cargo publishing context. ## v0.17.3 - Align the Readme's contribution guidance with Bake Readme conventions. -- Remove the local Bake alias and install the launcher explicitly for repository - tasks. +- Remove the local Bake alias and install the launcher explicitly for repository tasks. - Require complete line coverage in CI with the standard Bake coverage task. ## v0.17.2