From d75771d3d2e8167f0c062549afef0f1d04e6b3a9 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Mon, 29 Jun 2026 17:08:26 -0400 Subject: [PATCH 1/6] build(release): add publish metadata and cargo-release tooling --- .github/workflows/release.yml | 42 +++++++++++++++++++++++++++++++++++ Cargo.toml | 6 +++++ release.toml | 9 ++++++++ 3 files changed, 57 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 release.toml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3a23f04 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,42 @@ +name: Release + +on: + push: + tags: ["v*"] + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: write + +jobs: + semver-checks: + name: Semver Checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - uses: obi1kenobi/cargo-semver-checks-action@v2 + with: + package: simple_doip + + publish: + name: Publish to crates.io + needs: semver-checks + # GATED: enable by setting repo variable SIMPLE_DOIP_PUBLISH_ENABLED=true + # once #925's proxy is live and CARGO_REGISTRY_TOKEN exists in secrets. + if: github.event_name == 'push' && vars.SIMPLE_DOIP_PUBLISH_ENABLED == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo install cargo-release --version 0.25 --locked + - run: cargo release publish --workspace --no-confirm --execute + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} diff --git a/Cargo.toml b/Cargo.toml index 0551c3d..45d0e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,12 @@ name = "simple_doip" version = "0.1.0" edition = "2024" +description = "DoIP (Diagnostics over IP, ISO 13400) protocol implementation" +license = "MIT OR Apache-2.0" +repository = "https://github.com/luminartech/simple_doip" +readme = "README.md" +keywords = ["doip", "iso13400", "diagnostics", "automotive", "uds"] +categories = ["network-programming"] [dependencies] async-trait = "0.1" diff --git a/release.toml b/release.toml new file mode 100644 index 0000000..11e8dab --- /dev/null +++ b/release.toml @@ -0,0 +1,9 @@ +# cargo-release config for the standalone simple_doip repo. +shared-version = false +publish = false # CI owns publishing +registry = "crates-io" # source of truth under Option B +tag-name = "v{{version}}" +tag-message = "simple_doip v{{version}}" +pre-release-commit-message = "chore(release): v{{version}}" +allow-branch = ["main"] +pre-release-hook = ["cargo", "test", "--workspace", "--locked"] From f73199274fdbc3908d9946118ef0b2bc8e61d8e7 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Mon, 29 Jun 2026 17:13:18 -0400 Subject: [PATCH 2/6] ci: pin cargo-release with a valid version requirement --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3a23f04..2fb362e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,7 @@ jobs: fetch-depth: 0 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: cargo install cargo-release --version 0.25 --locked + - run: cargo install cargo-release --version '^0.25' --locked - run: cargo release publish --workspace --no-confirm --execute env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} From a4c9e9b54ea912a25c08fe3d3371ca097113cbcd Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Tue, 30 Jun 2026 04:32:47 -0400 Subject: [PATCH 3/6] ci: allow publish from detached HEAD on tag push (--allow-branch '*') --- .github/workflows/release.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2fb362e..4f5f8cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,6 +37,9 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo install cargo-release --version '^0.25' --locked - - run: cargo release publish --workspace --no-confirm --execute + # --allow-branch '*': a tag-push CI run is in detached-HEAD state, which + # cargo-release's branch check would otherwise reject. Publishing is + # already gated by the job `if:` above; this only relaxes the ref check. + - run: cargo release publish --workspace --allow-branch '*' --no-confirm --execute env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} From 401166ecf789abff2e0234c8ec64c9619185bac8 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Fri, 10 Jul 2026 11:09:57 -0400 Subject: [PATCH 4/6] fix: resolve clippy::pedantic errors on 1.96 (duration units + doc backticks) Newer clippy (1.96) flags two pedantic lints on existing code that the robust-CI job now enforces with -Dclippy::pedantic: - duration_suboptimal_units: use from_secs/from_mins over smaller units (from_millis(5000)->from_secs(5), from_secs(120)->from_mins(2), from_secs(300)->from_mins(5)) - all values unchanged. - doc_markdown: backtick DoIP, DoIPInt, and SendDiagnosticMessage in docs. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/client.rs | 3 +-- src/client_inner.rs | 4 ++-- src/connection.rs | 4 ++-- src/lib.rs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/client.rs b/src/client.rs index 355b969..4aa1b68 100644 --- a/src/client.rs +++ b/src/client.rs @@ -217,8 +217,7 @@ where pub async fn reconnect(&mut self) -> Result, Error> { let _ = Self::bind_socket(&self.control_sender, &self.client_options).await?; trace!("Reconnected, checking for in-flight messages over 5 seconds"); - let res = - tokio::time::timeout(Duration::from_millis(5000), self.update_receiver.recv()).await; + let res = tokio::time::timeout(Duration::from_secs(5), self.update_receiver.recv()).await; // Elapsed error handling, no response in flight let Ok(res) = res else { return Ok(None); diff --git a/src/client_inner.rs b/src/client_inner.rs index 159edf3..eba6996 100644 --- a/src/client_inner.rs +++ b/src/client_inner.rs @@ -35,13 +35,13 @@ pub(super) enum ControlMessage { oneshot::Sender>, ), - /// Send diagnostic message and wait for DoIP ACK only (not full response) + /// Send diagnostic message and wait for `DoIP` ACK only (not full response) SendDiagnosticMessage(Message, oneshot::Sender>), /// Wait for next diagnostic response (no send) ReceiveDiagnosticResponse(std::time::Duration, oneshot::Sender>), - /// Internal: waiting for ACK only (after SendDiagnosticMessage) + /// Internal: waiting for ACK only (after `SendDiagnosticMessage`) AwaitAck(oneshot::Sender>), } diff --git a/src/connection.rs b/src/connection.rs index 1fd1bf6..9b52b82 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -122,7 +122,7 @@ impl Connector for ConnectorSocket { /// Establishes a connection via a TCP listener socket. /// /// Instead of connecting to a remote server, this connector binds to the given -/// address and waits for an incoming connection. This is used for DoIPInt (VCC) +/// address and waits for an incoming connection. This is used for `DoIPInt` (VCC) /// where the sensor initiates the TCP connection to the tester. #[derive(Clone, Debug)] pub struct ListenerSocket; @@ -158,7 +158,7 @@ impl Connector for ListenerSocket { let tcp_listener = tcp_socket.listen(1)?; let local_addr = tcp_listener.local_addr()?; debug!("DoIPInt entity listening on {local_addr}"); - let result = tokio::time::timeout(Duration::from_secs(120), tcp_listener.accept()).await; + let result = tokio::time::timeout(Duration::from_mins(2), tcp_listener.accept()).await; // Drop the listener once connected so other processes can bind to the same port drop(tcp_listener); diff --git a/src/lib.rs b/src/lib.rs index ee718ed..4d3ad73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,7 @@ pub const TCP_TIMEOUT_INITIAL_INACTIVITY: time::Duration = time::Duration::from_ /// General inactivity timeout for TCP connections. Timeout is 300 seconds (5 minutes). /// /// If no data is sent or received for this duration, the connection is closed by the `DoIP` entity -pub const TCP_TIMEOUT_GENERAL_INACTIVITY: time::Duration = time::Duration::from_secs(300); +pub const TCP_TIMEOUT_GENERAL_INACTIVITY: time::Duration = time::Duration::from_mins(5); /// Alive check for the maximum amount of time an entity waits for an alive check response after having /// made an alive check request. Timeout is 5 seconds. From df3e8bb759e25e1963f6b1fec2dfa0f1f11ea842 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Fri, 10 Jul 2026 11:09:57 -0400 Subject: [PATCH 5/6] ci(release): gate semver-checks behind SIMPLE_DOIP_PUBLISH_ENABLED cargo-semver-checks needs a published baseline on the registry to diff against; simple_doip has never been published, so the check errors with "not found in registry (crates.io)". Gate it behind the same variable that already gates publish - there is no baseline to check until the first publish happens, once #925's Kellnr proxy is live. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4f5f8cb..55003ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,11 @@ permissions: jobs: semver-checks: name: Semver Checks + # GATED alongside publish: cargo-semver-checks needs a published baseline on + # the registry to diff against, which doesn't exist until the first publish. + # Enable by setting SIMPLE_DOIP_PUBLISH_ENABLED=true once #925's proxy is + # live and a baseline version has been published. + if: vars.SIMPLE_DOIP_PUBLISH_ENABLED == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 From 88e4503f6c23a02b01edbbf7ff6e84c4a0cd409b Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Mon, 13 Jul 2026 10:44:29 -0400 Subject: [PATCH 6/6] docs(release): refresh publish-gate comments Drop the stale "once #925's proxy is live" precondition from the semver-checks and publish gate comments. Publishing to crates.io needs only CARGO_REGISTRY_TOKEN + crates.io reachability; the Kellnr crates.io proxy fronts crates.io for dft-side consumption of the published crate, a separate concern. The real gate is the token + the decision to cut a first version (semver-checks also needs a published baseline to exist first). Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 55003ba..539a8dd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,8 +14,8 @@ jobs: name: Semver Checks # GATED alongside publish: cargo-semver-checks needs a published baseline on # the registry to diff against, which doesn't exist until the first publish. - # Enable by setting SIMPLE_DOIP_PUBLISH_ENABLED=true once #925's proxy is - # live and a baseline version has been published. + # Enable by setting SIMPLE_DOIP_PUBLISH_ENABLED=true once a baseline version + # has been published to crates.io. if: vars.SIMPLE_DOIP_PUBLISH_ENABLED == 'true' runs-on: ubuntu-latest steps: @@ -32,7 +32,10 @@ jobs: name: Publish to crates.io needs: semver-checks # GATED: enable by setting repo variable SIMPLE_DOIP_PUBLISH_ENABLED=true - # once #925's proxy is live and CARGO_REGISTRY_TOKEN exists in secrets. + # once CARGO_REGISTRY_TOKEN exists in secrets and the team decides to cut a + # first version. Publishing goes to crates.io and needs only the token + + # crates.io reachability — not the Kellnr proxy (that fronts crates.io for + # dft-side consumption of the published crate, a separate concern). if: github.event_name == 'push' && vars.SIMPLE_DOIP_PUBLISH_ENABLED == 'true' runs-on: ubuntu-latest steps: