mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-13 18:54:45 +00:00
Prepare the first coordinated craft-libs release
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
name: Workspace
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
tags: ["v*"]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
native:
|
||||
name: Workspace (${{ matrix.os }})
|
||||
timeout-minutes: 30
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install software Vulkan renderer
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y mesa-vulkan-drivers libvulkan1
|
||||
echo 'WGPU_BACKEND=vulkan' >> "$GITHUB_ENV"
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt, clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: workspace
|
||||
- name: Prepare the Windows test driver
|
||||
if: runner.os == 'Windows'
|
||||
shell: powershell
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Start-Service Spooler
|
||||
Add-PrinterDriver -Name 'Generic / Text Only'
|
||||
- run: cargo fmt --check
|
||||
- run: cargo clippy --workspace --all-targets --locked -- -D warnings
|
||||
- run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
|
||||
- run: cargo test --workspace --locked
|
||||
env:
|
||||
CRAFT_PRINT_REQUIRE_QUEUE: ${{ runner.os == 'Windows' && '1' || '0' }}
|
||||
- run: cargo test --workspace --all-features --locked
|
||||
env:
|
||||
CRAFT_PRINT_REQUIRE_QUEUE: ${{ runner.os == 'Windows' && '1' || '0' }}
|
||||
msrv:
|
||||
name: Rust 1.95 (Linux libraries)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@1.95.0
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: workspace-msrv
|
||||
- run: cargo check --workspace --lib --all-features --locked
|
||||
wasm:
|
||||
name: UI and settings WASM
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
key: workspace-wasm
|
||||
- run: cargo check -p craft-ui -p craft-settings --all-features --locked --target wasm32-unknown-unknown
|
||||
@@ -0,0 +1,65 @@
|
||||
# Changelog
|
||||
|
||||
All crates share the workspace version. See [the versioning policy](docs/versioning.md).
|
||||
|
||||
## v0.1.0 — 2026-10-12
|
||||
|
||||
First coordinated Git release of craft-libs. Applications can pin a named baseline instead of
|
||||
following development commits. This is an initial 0.x release: compatibility is maintained
|
||||
within `0.1.x`; changes requiring consumer migration use a new minor version.
|
||||
|
||||
### Included crates
|
||||
|
||||
- **craft-atomic:** same-directory staged file replacement, exclusive creation, streaming
|
||||
writes, transient rename retries and fault-injection support, extracted from PhotoCraft.
|
||||
- **craft-settings:** app-owned TOML settings with platform/portable paths, atomic saves,
|
||||
backups, damaged-file recovery, schema migrations and preservation of unknown fields.
|
||||
- **craft-quit:** native macOS termination, optional egui close handling and an optional
|
||||
application menu. Save decisions and prompts stay with the app.
|
||||
- **craft-print:** CUPS and native Windows PDF submission, printer discovery, copies, duplex,
|
||||
colour and scaling options. Includes bounded PDF sheet handling and the pinned Windows
|
||||
completion fix. PDF generation stays with the app.
|
||||
- **craft-ui:** egui icon buttons, tabs, splits, resize handles, toolbar overflow, transactional
|
||||
docking, theme helpers and print-settings controls. Commands, content, localization and
|
||||
application state stay with the consumer. Docking serialization is opt-in through `serde`.
|
||||
|
||||
### Requirements and adoption
|
||||
|
||||
- Rust **1.95+**, edition 2024. Public UI integrations use **egui 0.36**.
|
||||
- Use `git = "https://github.com/storytold/craft-libs", tag = "v0.1.0"` for each required crate;
|
||||
use the same tag everywhere. The [README](README.md#use-a-released-version) has a complete
|
||||
manifest example and a commit-pin alternative. Commit application lockfiles.
|
||||
- No automatic migration from an arbitrary earlier Git revision is implied. Compare the API
|
||||
you used with this release and test affected workflows before changing pins.
|
||||
- For `craft-quit`, run the close hook last in `eframe::App::logic`, after the app's unsaved-work
|
||||
decision. Finish asynchronous saves before requesting close; termination does not execute
|
||||
code after `run_native`. See the crate's API documentation before adoption.
|
||||
- This release is distributed through Git only. No crates.io packages are published by it.
|
||||
|
||||
### Platform coverage and known limits
|
||||
|
||||
The release gate checks the workspace on Linux, macOS and Windows with default and all features,
|
||||
plus Linux minimum-compiler and UI/settings WASM checks. UI tests include offscreen visual
|
||||
regressions. Windows print tests exercise a temporary paused spooler queue; those checks do
|
||||
not establish physical printer fidelity or every application's native GUI behavior.
|
||||
|
||||
- `craft-ui` supports native and WASM use. Font coverage, bidirectional text and screen-reader
|
||||
behavior still depend on the application and upstream stack; see [#17](https://github.com/storytold/craft-libs/issues/17).
|
||||
- `craft-settings` persistence is native-only. WASM exposes settings traits, document helpers
|
||||
and error types. Concurrent writers are best-effort, last-writer-wins; strict coordination
|
||||
needs an application-owned lock.
|
||||
- `craft-atomic` does not preserve all filesystem metadata during replacement. Directory sync
|
||||
is best effort; tests do not prove physical power-loss durability. See its README's contract.
|
||||
- `craft-quit`'s native behavior is macOS-specific; other platforms keep their normal close
|
||||
path. Earlier hardware testing of the close hook is recorded in
|
||||
[#3](https://github.com/storytold/craft-libs/issues/3); it does not qualify every consuming app.
|
||||
- `craft-print` requires CUPS command-line tools on Linux/macOS or the native Windows spooler.
|
||||
Browser submission is unsupported. Windows accepts a bounded subset of print-ready PDFs;
|
||||
unsupported inputs and driver paper/scaling mismatches return errors. Printing is synchronous,
|
||||
so call it from a worker. Physical output needs hardware testing.
|
||||
- Windows printing retains a pinned Git dependency on the maintained `winprint` fork. Its
|
||||
build dependencies require the license/advisory policy exceptions documented in
|
||||
[craft-print's README](crates/print/README.md). Registry publication is deferred.
|
||||
|
||||
Planned crates and open feature PRs are not part of this release. Existing commit pins remain
|
||||
valid, and consumers do not need to update simply because `main` changes.
|
||||
@@ -15,12 +15,41 @@ A Cargo workspace (edition 2024, resolver 3). Each library is a crate under `cra
|
||||
(`license.workspace = true`, and so on) and `[lints] workspace = true`. Register each crate in
|
||||
`[workspace.dependencies]` in the root `Cargo.toml`.
|
||||
|
||||
Apps depend on a crate by git:
|
||||
## Use a released version
|
||||
|
||||
The first coordinated release is **[v0.1.0](https://github.com/storytold/craft-libs/releases/tag/v0.1.0)**.
|
||||
It gives consumers a fixed baseline while development continues on `main`. All five crates
|
||||
share this version. They require Rust 1.95 or later; the UI integrations use egui 0.36.
|
||||
|
||||
Add only the crates you need, using the same tag for every craft-libs dependency:
|
||||
|
||||
```toml
|
||||
craft-<name> = { git = "https://github.com/storytold/craft-libs", rev = "<commit>" }
|
||||
[dependencies]
|
||||
craft-ui = { git = "https://github.com/storytold/craft-libs", tag = "v0.1.0" }
|
||||
craft-settings = { git = "https://github.com/storytold/craft-libs", tag = "v0.1.0" }
|
||||
# Optional, for egui close handling and the macOS application menu:
|
||||
craft-quit = { git = "https://github.com/storytold/craft-libs", tag = "v0.1.0", features = ["menu"] }
|
||||
```
|
||||
|
||||
`craft-atomic` and `craft-print` use the same dependency syntax. Enable `craft-ui`'s
|
||||
`serde` feature if you need to serialize its docking layout. These are Git releases;
|
||||
crates.io publication is deferred.
|
||||
|
||||
Release tags are never moved or reused. For a commit pin, resolve the tag with
|
||||
`git ls-remote https://github.com/storytold/craft-libs 'refs/tags/v0.1.0^{}'` and replace
|
||||
`tag = "v0.1.0"` with `rev = "<full commit SHA>"` on every craft-libs dependency.
|
||||
Use either `tag` or `rev`, not both. An existing commit pin keeps working; switching to this
|
||||
release may require adapting to changes since that commit.
|
||||
|
||||
Commit your application's `Cargo.lock` and build with `cargo build --locked` for reproducible
|
||||
Rust dependency resolution. A Git pin fixes craft-libs source, not every transitive dependency.
|
||||
A library's own lockfile does not constrain its downstream consumers. Upgrade deliberately:
|
||||
read the release notes, update all craft-libs pins together, refresh the lockfile with
|
||||
`cargo check`, and run your application's tests and affected workflows before committing.
|
||||
|
||||
See the [release notes](CHANGELOG.md) for included functionality and known limits, and the
|
||||
[versioning policy](docs/versioning.md) for compatibility guarantees and release checks.
|
||||
|
||||
## Libraries
|
||||
|
||||
- [`craft-atomic`](crates/atomic/README.md): Crash-safe atomic file writing and replacement with same-directory staging, directory fsync, Apple `F_FULLFSYNC` fallback, transient lock backoff, and fault injection for the Craft suite.
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# Versioning and releases
|
||||
|
||||
craft-libs releases give applications a fixed dependency baseline. Consumers decide when to
|
||||
upgrade; development on `main` is not a reason to refresh a working application's pins.
|
||||
|
||||
## One workspace, one release
|
||||
|
||||
All crates inherit `workspace.package.version` and ship together under an annotated `vX.Y.Z`
|
||||
Git tag. A release contains the crates listed in that tag's README, not proposed crates in
|
||||
open pull requests. A crate can keep the same implementation across several workspace releases.
|
||||
Use the same tag or commit for every craft-libs dependency in a consumer's dependency graph;
|
||||
mixing Git sources can create duplicate crate instances and incompatible Rust types.
|
||||
|
||||
Tags identify reviewed commits and are never moved, deleted or reused to fix a release.
|
||||
Corrections get a new version. The release notes and policy are stored with the source so a
|
||||
consumer can read the contract that applied to its version. GitHub Releases carry the same notes.
|
||||
Publishing to crates.io will be a separate step; these tags do not imply registry availability.
|
||||
|
||||
## Compatibility while versions are 0.x
|
||||
|
||||
The initial release is `0.1.0`. APIs are still developing, but compatibility within a minor
|
||||
release line is intentional:
|
||||
|
||||
- **Patch (`0.1.0` → `0.1.1`):** compatible fixes, documentation and additive APIs that preserve
|
||||
existing callers. Keep public signatures, feature defaults, supported targets, minimum Rust
|
||||
version and documented behavior compatible. Check that additions do not break exhaustive
|
||||
matches, struct literals, trait implementations or other existing source patterns.
|
||||
- **Minor (`0.1.x` → `0.2.0`):** changes requiring consumer action. This includes removing or
|
||||
changing public APIs, incompatible persisted representations, feature/default changes,
|
||||
dropping a supported target, raising the minimum Rust version, or upgrading a dependency
|
||||
such as egui when its exposed types become incompatible. Explain the before/after and migration.
|
||||
- **`1.0.0`:** a separate decision that the public contracts are ready for long-term stability.
|
||||
After that, breaking changes require a major release; compatible additions use minor releases.
|
||||
|
||||
Documented invalid input can be rejected more strictly in a patch to fix a defect or security
|
||||
issue. Call out any observable change. Do not use “0.x” or “bug fix” to silently break a valid,
|
||||
documented workflow. App-owned settings schemas and migration policy remain the app's
|
||||
responsibility; library releases do not automatically migrate consumer data.
|
||||
|
||||
For public egui APIs in `0.1.x`, keep the egui 0.36 compatibility line. The minimum Rust version
|
||||
is 1.95. Compatible transitive updates still need validation and release-note coverage when
|
||||
observable. Cargo's version-range rules do not select newer Git tags: changing a release pin
|
||||
is always an explicit manifest edit.
|
||||
|
||||
## Support and scope
|
||||
|
||||
The newest minor line receives routine fixes. Important fixes to older lines are considered
|
||||
case by case; there is no promise of maintaining every 0.x line or an LTS schedule. Existing
|
||||
tags remain available so consumers can upgrade on their own schedule. Release notes identify
|
||||
known limitations; a tag is not a claim that every driver, OS version or consuming app was tested.
|
||||
|
||||
Platform boundaries are crate-specific. See each crate's API/README and the release notes.
|
||||
In particular, native printing needs the OS spooler, settings persistence is native-only, and
|
||||
browser UI compatibility does not imply native services work in a browser. Consumers must test
|
||||
their own save/close flows, accessibility, rendering and printing where they use those services.
|
||||
|
||||
## Preparing a release
|
||||
|
||||
1. Choose a reviewed commit on `main`. Inspect open defects, changes since the previous tag,
|
||||
crate metadata and any changed platform/dependency contracts. Update the shared version
|
||||
and lockfile when needed; the first release already uses `0.1.0`.
|
||||
2. Add a dated `CHANGELOG.md` entry with the included crates, changes, compatibility requirements,
|
||||
migration steps and known limits. Update the README's recommended pin. Keep fixes and
|
||||
unrelated pending features out of the release preparation unless they block the baseline.
|
||||
3. Run formatting, workspace Clippy with warnings denied, and workspace tests, both default
|
||||
and all features. The `Workspace` workflow runs these on Linux, macOS and Windows, requires
|
||||
Windows spooler regression tests, checks the minimum compiler on Linux, and checks the
|
||||
documented UI/settings WASM surface. All release jobs must pass for the candidate source.
|
||||
Repository-local build commands must also follow the host's storage/allocation rules.
|
||||
4. Review consumer impact and existing platform evidence. Exercise affected native workflows
|
||||
when behavior changes; unit tests and cross-compilation cannot establish GUI or physical
|
||||
printer acceptance. Record limitations instead of extending the support claim beyond evidence.
|
||||
5. Merge the preparation PR and verify the checks for the actual release commit. Create an
|
||||
annotated tag on that exact commit (`git tag -a vX.Y.Z FULL_SHA -m "craft-libs vX.Y.Z"`),
|
||||
push only that tag, and create a GitHub Release using that version's changelog entry.
|
||||
Tag-triggered CI should also pass. Do not publish crates as part of this Git-only release.
|
||||
6. Verify that the remote tag resolves to the intended commit, the release notes are visible,
|
||||
and a small external consumer resolves and checks with the documented pin. Preserve the
|
||||
source identity, check results and release URL. Never repair a published tag by moving it.
|
||||
|
||||
The workflow validates source; it does not automatically tag or publish on every push.
|
||||
Reference in New Issue
Block a user