From 016de9f26ee2bb4cf4408ebbbc26d7efcddd96dc Mon Sep 17 00:00:00 2001 From: RA <70325462+RAprogramm@users.noreply.github.com> Date: Sat, 20 Sep 2025 20:25:46 +0700 Subject: [PATCH] Prepare release with derive re-export --- .github/workflows/release.yml | 47 ++++++++++++++++++++++--- CHANGELOG.md | 8 +++++ Cargo.lock | 4 +-- Cargo.toml | 6 ++-- README.md | 15 ++++---- masterror-derive/Cargo.toml | 3 +- src/lib.rs | 65 ++++++++++------------------------- 7 files changed, 82 insertions(+), 66 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 334792f..0a63a9c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,6 @@ jobs: steps: - uses: actions/checkout@v4 - # Install a minimal Rust toolchain so that `cargo metadata` is available. - name: Install Rust (stable, minimal) uses: dtolnay/rust-toolchain@v1 with: @@ -50,7 +49,6 @@ jobs: echo "rust-version is not set for crate: ${CRATE_NAME}" exit 1 fi - # Normalize X.Y to X.Y.0 if [[ "$RV" =~ ^[0-9]+\.[0-9]+$ ]]; then RV="${RV}.0" fi @@ -84,8 +82,49 @@ jobs: with: toolchain: ${{ steps.msrv.outputs.msrv }} - - name: Publish to crates.io + - name: Maybe publish masterror-derive env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - run: cargo +${{ steps.msrv.outputs.msrv }} publish --locked --token "$CARGO_REGISTRY_TOKEN" + shell: bash + run: | + set -euo pipefail + if cargo metadata --no-deps --format-version=1 \ + | jq -e '.packages[] | select(.name=="masterror-derive" and .source==null)' >/dev/null; then + echo "Publishing masterror-derive..." + n=0 + until [ $n -ge 5 ] + do + if cargo +${{ steps.msrv.outputs.msrv }} publish -p masterror-derive --locked --token "$CARGO_REGISTRY_TOKEN"; then + echo "masterror-derive published." + break + fi + n=$((n+1)) + echo "Retry $n/5 for masterror-derive..." + sleep $((5*n)) + done + else + echo "No local masterror-derive found; skipping." + fi + + - name: Wait for crates.io index sync + run: sleep 15 + - name: Publish masterror + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + shell: bash + run: | + set -euo pipefail + n=0 + until [ $n -ge 5 ] + do + if cargo +${{ steps.msrv.outputs.msrv }} publish -p masterror --locked --token "$CARGO_REGISTRY_TOKEN"; then + echo "masterror published." + exit 0 + fi + n=$((n+1)) + echo "Retry $n/5 for masterror..." + sleep $((10*n)) + done + echo "Failed to publish masterror after retries." + exit 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index b8c1fbf..286bbe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [0.10.5] - 2025-09-20 + +### Added +- Re-exported `masterror-derive` macros from `masterror` so consumers only depend on a single crate while deriving application errors. + +### Changed +- Published `masterror-derive` as a standalone crate (`0.6.1`) and configured the release workflow to publish it before `masterror` with retries and tag/MSRV validation. + ### Documentation - Described `#[provide]` telemetry providers and `#[app_error]` conversions with end-to-end examples in the derive guide ([README](README.md#structured-telemetry-providers-and-apperror-mappings), diff --git a/Cargo.lock b/Cargo.lock index 2e73446..f9dc7cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1606,7 +1606,7 @@ dependencies = [ [[package]] name = "masterror" -version = "0.10.4" +version = "0.10.5" dependencies = [ "actix-web", "axum", @@ -1636,7 +1636,7 @@ dependencies = [ [[package]] name = "masterror-derive" -version = "0.6.0" +version = "0.6.1" dependencies = [ "masterror-template", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index fbd06cf..32b82e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "masterror" -version = "0.10.4" +version = "0.10.5" rust-version = "1.90" edition = "2024" license = "MIT OR Apache-2.0" @@ -71,11 +71,11 @@ turnkey = [] openapi = ["dep:utoipa"] [workspace.dependencies] -masterror-derive = { version = "0.6.0" } +masterror-derive = { version = "0.6.1" } masterror-template = { version = "0.3.1" } [dependencies] -masterror-derive = { workspace = true } +masterror-derive = { version = "0.6" } masterror-template = { workspace = true } tracing = "0.1" diff --git a/README.md b/README.md index bb5ec5f..9c24e8f 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ Stable categories, conservative HTTP mapping, no `unsafe`. ~~~toml [dependencies] -masterror = { version = "0.10.4", default-features = false } +masterror = { version = "0.10.5", default-features = false } # or with features: -# masterror = { version = "0.10.4", features = [ +# masterror = { version = "0.10.5", features = [ # "axum", "actix", "openapi", "serde_json", # "sqlx", "sqlx-migrate", "reqwest", "redis", # "validator", "config", "tokio", "multipart", @@ -66,10 +66,10 @@ masterror = { version = "0.10.4", default-features = false } ~~~toml [dependencies] # lean core -masterror = { version = "0.10.4", default-features = false } +masterror = { version = "0.10.5", default-features = false } # with Axum/Actix + JSON + integrations -# masterror = { version = "0.10.4", features = [ +# masterror = { version = "0.10.5", features = [ # "axum", "actix", "openapi", "serde_json", # "sqlx", "sqlx-migrate", "reqwest", "redis", # "validator", "config", "tokio", "multipart", @@ -623,13 +623,13 @@ assert_eq!(resp.status, 401); Minimal core: ~~~toml -masterror = { version = "0.10.4", default-features = false } +masterror = { version = "0.10.5", default-features = false } ~~~ API (Axum + JSON + deps): ~~~toml -masterror = { version = "0.10.4", features = [ +masterror = { version = "0.10.5", features = [ "axum", "serde_json", "openapi", "sqlx", "reqwest", "redis", "validator", "config", "tokio" ] } @@ -638,7 +638,7 @@ masterror = { version = "0.10.4", features = [ API (Actix + JSON + deps): ~~~toml -masterror = { version = "0.10.4", features = [ +masterror = { version = "0.10.5", features = [ "actix", "serde_json", "openapi", "sqlx", "reqwest", "redis", "validator", "config", "tokio" ] } @@ -709,4 +709,3 @@ MSRV = 1.90 (may raise in minor, never in patch). Apache-2.0 OR MIT, at your option. - diff --git a/masterror-derive/Cargo.toml b/masterror-derive/Cargo.toml index 1687e51..d764ec5 100644 --- a/masterror-derive/Cargo.toml +++ b/masterror-derive/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "masterror-derive" rust-version = "1.90" -version = "0.6.0" +version = "0.6.1" edition = "2024" license = "MIT OR Apache-2.0" repository = "https://github.com/RAprogramm/masterror" readme = "README.md" description = "Derive macros for masterror" -publish = false [lib] proc-macro = true diff --git a/src/lib.rs b/src/lib.rs index 4e6fceb..e8aa708 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -206,60 +206,31 @@ pub mod prelude; pub use app_error::{AppError, AppResult}; pub use code::AppCode; pub use kind::AppErrorKind; -/// Native derive macro for error enums and structs. +/// Re-export derive macros so users only depend on [`masterror`]. /// -/// Supports `#[from]` conversions, transparent wrappers, and precise -/// diagnostics for `#[error("...")]` templates with field-aware validation. +/// # Examples /// /// ``` -/// use std::error::Error as StdError; -/// -/// use masterror::Error; +/// use masterror::{AppCode, AppError, AppErrorKind, Error}; /// /// #[derive(Debug, Error)] -/// #[error("{code}: {message}")] -/// struct MiniError { -/// code: u16, -/// message: &'static str +/// #[error("missing flag: {name}")] +/// #[app_error(kind = AppErrorKind::BadRequest, code = AppCode::BadRequest, message)] +/// struct MissingFlag { +/// name: &'static str /// } /// -/// #[derive(Debug, Error)] -/// #[error("wrapper -> {0}")] -/// struct MiniWrapper( -/// #[from] -/// #[source] -/// MiniError -/// ); -/// -/// #[derive(Debug, Error)] -/// #[error(transparent)] -/// struct MiniTransparent(#[from] MiniError); -/// -/// let wrapped = MiniWrapper::from(MiniError { -/// code: 500, -/// message: "boom" -/// }); -/// assert_eq!(wrapped.to_string(), "wrapper -> 500: boom"); -/// assert_eq!( -/// StdError::source(&wrapped).map(|err| err.to_string()), -/// Some(String::from("500: boom")) -/// ); -/// -/// let expected_source = StdError::source(&MiniError { -/// code: 503, -/// message: "oops" -/// }) -/// .map(|err| err.to_string()); +/// let app: AppError = MissingFlag { +/// name: "feature" +/// } +/// .into(); +/// assert!(matches!(app.kind, AppErrorKind::BadRequest)); /// -/// let transparent = MiniTransparent::from(MiniError { -/// code: 503, -/// message: "oops" -/// }); -/// assert_eq!(transparent.to_string(), "503: oops"); -/// assert_eq!( -/// StdError::source(&transparent).map(|err| err.to_string()), -/// expected_source -/// ); +/// let code: AppCode = MissingFlag { +/// name: "other" +/// } +/// .into(); +/// assert!(matches!(code, AppCode::BadRequest)); /// ``` -pub use masterror_derive::Error; +pub use masterror_derive::*; pub use response::{ErrorResponse, RetryAdvice};