Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
73bbfdc
chore(deps): update tinybus submodule commit
senamakel Aug 10, 2026
697210e
feat(cargo): add TinyBus module feature for dynamic library loading
senamakel Aug 10, 2026
6be3ade
chore(deps): add async-trait, tokio, and tracing dependencies for bus…
senamakel Aug 10, 2026
bf7b69d
feat(bus): add TinyBus module support with CI and release automation
senamakel Aug 10, 2026
0cc9720
fix(diagram): correct tree‑drawing character for docx directory
senamakel Aug 10, 2026
665ad2f
fix(bus): wrap generated C ABI symbols in a private module
senamakel Aug 10, 2026
682d01d
fix(test): backtick-quote module and bus names in e2e test doc comment
senamakel Aug 10, 2026
ade3153
fix(bus): remove broken intra-doc link in module docs
senamakel Aug 10, 2026
d27f28e
refactor: extract TinyBus module into a separate workspace crate
senamakel Aug 10, 2026
9056853
refactor: extract TinyBus module into a private workspace crate
senamakel Aug 10, 2026
547baea
chore: files changed Cargo.toml
senamakel Aug 10, 2026
9302965
chore(tinydocs-module): reorder imports and update dependencies
senamakel Aug 10, 2026
6fd5f55
feat(service): add catch-all error mapping for unknown errors
senamakel Aug 10, 2026
64e8b9c
ci: add file-level coverage enforcement and extend release pipeline
senamakel Aug 10, 2026
873d193
chore: files changed .github/workflows/release.yml
senamakel Aug 10, 2026
9e438d7
chore(ci): make check-file-coverage.sh executable
senamakel Aug 10, 2026
81b208e
docs: update coverage threshold and release bundle descriptions
senamakel Aug 10, 2026
6607b10
chore: remove coverage.json
senamakel Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Commands actually run, with their outcome:
- [ ] `cargo clippy --all-targets --all-features -- -D warnings`
- [ ] `cargo build --all-targets --all-features`
- [ ] `cargo test --all-features`
- [ ] `.github/scripts/check-file-coverage.sh 90 coverage.json`

## Tests

Expand Down
73 changes: 73 additions & 0 deletions .github/scripts/check-file-coverage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -euo pipefail

minimum="${1:-90}"
report="${2:-coverage.json}"
workspace_root="$(pwd -P)/"
source_root="${workspace_root}src/"

cargo llvm-cov \
--locked \
--all-targets \
--all-features \
--json \
--output-path "$report"

covered_files="$(jq --arg source_root "$source_root" '
[
.data[].files[]
| select(.filename | startswith($source_root))
| select(.summary.lines.count > 0)
]
| length
' "$report")"

if [[ "$covered_files" -eq 0 ]]; then
echo "coverage report contains no files with executable lines under src/" >&2
exit 1
fi

summary="$(jq -r --arg workspace_root "$workspace_root" --arg source_root "$source_root" '
.data[].files[]
| select(.filename | startswith($source_root))
| select(.summary.lines.count > 0)
| [
(.filename | ltrimstr($workspace_root)),
(.summary.lines.percent | tostring),
(.summary.lines.covered | tostring),
(.summary.lines.count | tostring)
]
| @tsv
' "$report")"

printf 'File\tLine coverage\tCovered lines\tCoverable lines\n'
while IFS=$'\t' read -r file percent covered count; do
printf '%s\t%.2f%%\t%s\t%s\n' "$file" "$percent" "$covered" "$count"
done <<< "$summary"

if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then
{
printf '### Per-file line coverage\n\n'
printf '| File | Coverage | Lines |\n'
printf '| --- | ---: | ---: |\n'
while IFS=$'\t' read -r file percent covered count; do
printf '| %s | %.2f%% | %s/%s |\n' "$file" "$percent" "$covered" "$count"
done <<< "$summary"
} >> "$GITHUB_STEP_SUMMARY"
fi

failures="$(jq -r \
--arg workspace_root "$workspace_root" \
--arg source_root "$source_root" \
--argjson minimum "$minimum" '
.data[].files[]
| select(.filename | startswith($source_root))
| select(.summary.lines.count > 0)
| select(.summary.lines.percent < $minimum)
| "\(.filename | ltrimstr($workspace_root)): \(.summary.lines.percent)%"
' "$report")"

if [[ -n "$failures" ]]; then
printf '\nFiles below %s%% line coverage:\n%s\n' "$minimum" "$failures" >&2
exit 1
fi
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ jobs:
with:
components: rustfmt, clippy

- uses: taiki-e/install-action@cargo-llvm-cov

- uses: Swatinem/rust-cache@v2

- name: Check formatting
Expand All @@ -49,6 +51,38 @@ jobs:
- name: Test default features
run: cargo test

- name: Require 90% line coverage in every source file
run: .github/scripts/check-file-coverage.sh 90 coverage.json

- name: Upload coverage report
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: coverage-json
path: coverage.json
if-no-files-found: ignore

module-e2e:
name: TinyBus module E2E
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
submodules: true

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2

- name: Build the loadable module
run: cargo build --locked --release --package tinydocs-module

- name: Load the module and call GenerateDocx
env:
TINYDOCS_TEST_MODULE: ${{ github.workspace }}/target/release/libtinydocs_module.so
run: cargo test --locked --package tinydocs-module --test module_e2e -- --ignored

docs:
name: Docs
runs-on: ubuntu-latest
Expand Down
153 changes: 148 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ jobs:
if: ${{ github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
environment: Production
outputs:
crate_name: ${{ steps.version.outputs.crate_name }}
next_version: ${{ steps.version.outputs.next_version }}
tag: ${{ steps.version.outputs.tag }}
tinybus_version: ${{ steps.version.outputs.tinybus_version }}
steps:
- uses: actions/checkout@v7
with:
Expand All @@ -35,6 +40,8 @@ jobs:
with:
components: rustfmt, clippy

- uses: taiki-e/install-action@cargo-llvm-cov

- uses: Swatinem/rust-cache@v2

- name: Check formatting
Expand All @@ -46,6 +53,9 @@ jobs:
- name: Test
run: cargo test --all-features

- name: Require 90% line coverage in every source file
run: .github/scripts/check-file-coverage.sh 90 coverage.json

- name: Build documentation
env:
RUSTDOCFLAGS: -D warnings
Expand All @@ -58,12 +68,23 @@ jobs:
set -euo pipefail

metadata="$(cargo metadata --format-version 1 --no-deps)"
crate_name="$(jq -r '.packages[0].name' <<< "$metadata")"
current_version="$(jq -r '.packages[0].version' <<< "$metadata")"
crate_name="tinydocs"
current_version="$(jq -r '.packages[] | select(.name == "tinydocs") | .version' <<< "$metadata")"
tinybus_version="$(
cargo metadata \
--manifest-path vendor/tinybus/Cargo.toml \
--format-version 1 \
--no-deps \
| jq -r '.packages[] | select(.name == "tinybus") | .version'
)"
if [[ -z "$current_version" || "$current_version" == "null" ]]; then
echo "Could not resolve the current crate version" >&2
exit 1
fi
if [[ -z "$tinybus_version" || "$tinybus_version" == "null" ]]; then
echo "Could not resolve the TinyBus version" >&2
exit 1
fi

IFS=. read -r major minor patch <<< "$current_version"
case "${{ inputs.bump }}" in
Expand Down Expand Up @@ -99,6 +120,7 @@ jobs:
echo "current_version=${current_version}"
echo "next_version=${next_version}"
echo "tag=${tag}"
echo "tinybus_version=${tinybus_version}"
} >> "$GITHUB_OUTPUT"

- name: Update crate version
Expand All @@ -108,6 +130,7 @@ jobs:
run: |
set -euo pipefail
perl -0pi -e 's/(\[package\][\s\S]*?\nversion = ")[^"]+(")/$1$ENV{NEXT_VERSION}$2/' Cargo.toml
perl -0pi -e 's/(\[package\][\s\S]*?\nversion = ")[^"]+(")/$1$ENV{NEXT_VERSION}$2/' crates/tinydocs-module/Cargo.toml
cargo update -p "$CRATE_NAME" --precise "$NEXT_VERSION"
Comment on lines +113 to 114

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

workflow=.github/workflows/release.yml
grep -F 'cargo update --workspace' "$workflow"

Repository: tinyhumansai/tinydocs

Length of output: 159


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release workflow outline/sections =="
wc -l .github/workflows/release.yml
nl -ba .github/workflows/release.yml | sed -n '1,230p'

echo
echo "== version update and cargo update/search =="
rg -n "NEXT_VERSION|CRATE_NAME|tinydocs|Cargo.toml|cargo build|cargo publish|cargo test|cargo package|cargo update|--locked|--workspace" .github/workflows/release.yml crates -S

echo
echo "== workspace manifests =="
find crates -maxdepth 3 -name Cargo.toml -print | sort
for f in $(find crates -name Cargo.toml -print); do
  echo "--- $f"
  nl -ba "$f" | sed -n '1,80p'
done

Repository: tinyhumansai/tinydocs

Length of output: 273


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
workflow = Path(".github/workflows/release.yml")
lines = workflow.read_text().splitlines()
for i,l in enumerate(lines, 1):
    if "cargo update" in l or "perl -0pi" in l or "NEXT_VERSION" in l:
        print(f"{i}: {l}")
PY

Repository: tinyhumansai/tinydocs

Length of output: 544


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== release workflow relevant lines =="
awk '{printf "%6d\t%s\n", NR, $0}' .github/workflows/release.yml | sed -n '80,135p'

echo
echo "== version update and cargo update/search =="
grep -RInE "NEXT_VERSION|CRATE_NAME|tinydocs|Cargo.toml|cargo build|cargo publish|cargo test|cargo package|cargo update|--locked|--workspace" .github/workflows/release.yml crates 2>/dev/null || true

echo
echo "== workspace manifests =="
find crates -maxdepth 3 -name Cargo.toml -print 2>/dev/null | sort | while read -r f; do
  printf -- "--- %s\n" "$f"
  awk '{printf "%6d\t%s\n", NR, $0}' "$f" | sed -n '1,90p'
done

echo
echo "== root workspace Cargo.toml =="
if [ -f Cargo.toml ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' Cargo.toml
fi

Repository: tinyhumansai/tinydocs

Length of output: 11173


🌐 Web query:

Cargo cargo update --workspace after manifest version changes documentation

💡 Result:

The cargo update --workspace command is designed to update dependencies as recorded in the Cargo.lock file, specifically targeting packages defined within your workspace [1][2]. According to the official Cargo documentation, the --workspace (or -w) flag is primarily useful for updating Cargo.lock after you have manually changed version numbers in your Cargo.toml files [1][2]. When you use this flag, Cargo attempts to update only the packages defined in the workspace, while other packages are updated only if they do not already exist in the lockfile [1][3]. It is important to note that the cargo update command does not automatically modify or write to your Cargo.toml files to reflect new version requirements [4]. The command updates the dependency versions pinned in the Cargo.lock file based on the constraints already present in your manifest [2][5]. If you are looking to automatically update the version requirements inside your Cargo.toml files (e.g., upgrading a dependency to the latest version), you would typically use external tools like cargo-edit (specifically the cargo upgrade command) rather than cargo update [4][6]. In summary: - cargo update --workspace: Updates Cargo.lock to match changes you have already made in Cargo.toml [1][2]. - Cargo.toml changes: You must manually edit these or use other tools; cargo update will not update them for you [4].

Citations:


Update the whole workspace lock after the version edits.

The release workflow edits both Cargo.toml and crates/tinydocs-module/Cargo.toml, then records Cargo.lock and later uses --locked builds. cargo update -p "$CRATE_NAME" --precise "$NEXT_VERSION" only refreshes tinydocs; run cargo update --workspace instead so both workspace package entries in the lockfile stay aligned.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 113 - 114, Replace the targeted
cargo update command after the version edits with a workspace-wide update using
cargo update --workspace. Ensure the resulting Cargo.lock entries for both
modified workspace packages are aligned before subsequent --locked builds.


- name: Commit version bump and tag
Expand All @@ -117,12 +140,31 @@ jobs:
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Cargo.toml Cargo.lock
git add Cargo.toml Cargo.lock crates/tinydocs-module/Cargo.toml
git commit -m "Release ${RELEASE_TAG}"
git tag -a "${RELEASE_TAG}" -m "Release ${RELEASE_TAG}"

- name: Package crate
run: cargo package --locked
run: cargo package --locked --package tinydocs

- name: Package TinyBus source and module SDK
run: |
set -euo pipefail
tinybus_revision="$(git -C vendor/tinybus rev-parse --short=12 HEAD)"
git -C vendor/tinybus archive \
--format=tar.gz \
--prefix="tinybus-${tinybus_revision}/" \
--output="$PWD/target/package/tinybus-source-${tinybus_revision}.tar.gz" \
HEAD

- name: Upload source packages
uses: actions/upload-artifact@v4
with:
name: source-packages
path: |
target/package/${{ steps.version.outputs.crate_name }}-${{ steps.version.outputs.next_version }}.crate
target/package/tinybus-source-*.tar.gz
if-no-files-found: error

- name: Push release commit and tag
env:
Expand All @@ -133,6 +175,107 @@ jobs:
git push origin "${RELEASE_TAG}"

- name: Publish to crates.io
run: cargo publish --locked
run: cargo publish --locked --package tinydocs
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

native-bundles:
name: Native bundle (${{ matrix.os }})
needs: publish
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
with:
ref: ${{ needs.publish.outputs.tag }}
persist-credentials: false
submodules: true

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2
Comment on lines +158 to +166

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== workflow outline =="
wc -l .github/workflows/release.yml
sed -n '1,230p' .github/workflows/release.yml

echo
echo "== uses lines =="
rg -n '^\s+-\s+uses:\s+|uses:\s+' .github/workflows/release.yml

Repository: tinyhumansai/tinydocs

Length of output: 6765


Security Misconfiguration (CWE-829): Inclusion of Functionality from Untrusted Control Sphere

Reachability: Internal

Pin release-workflow actions to full commit SHAs.

The release workflow runs actions while resolving the release commit, building the module, and uploading assets that gh release create publishes as release assets. Mutable tag references like actions/checkout@v7, dtolnay/rust-toolchain@stable, Swatinem/rust-cache@v2, actions/upload-artifact@v4, and actions/download-artifact@v5 can execute changed upstream code in that trusted path. Pin each uses: reference to a reviewed full commit SHA.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 158 - 166, Pin every
release-workflow action reference—including actions/checkout,
dtolnay/rust-toolchain, Swatinem/rust-cache, actions/upload-artifact, and
actions/download-artifact—to reviewed immutable full commit SHAs, replacing the
mutable version tags while preserving each action’s existing configuration.

with:
workspaces: |
. -> target
vendor/tinybus -> target

- name: Build TinyBus host
working-directory: vendor/tinybus
run: cargo build --locked --release --package tinybus --all-features --bin tinybus

- name: Build TinyDocs module
run: cargo build --locked --release --package tinydocs-module

- name: Assemble native bundle
id: bundle
shell: bash
env:
TINYBUS_VERSION: ${{ needs.publish.outputs.tinybus_version }}
TINYDOCS_VERSION: ${{ needs.publish.outputs.next_version }}
run: |
set -euo pipefail

target_triple="$(rustc -vV | sed -n 's/^host: //p')"
bundle_name="tinydocs-${TINYDOCS_VERSION}-tinybus-${TINYBUS_VERSION}-${target_triple}"
bundle_root="dist/${bundle_name}"
module_root="${bundle_root}/modules"
mkdir -p "${bundle_root}/bin" "$module_root" "${bundle_root}/docs"

install -m 755 vendor/tinybus/target/release/tinybus "${bundle_root}/bin/tinybus"

module_artifact="$(find target/release -maxdepth 1 -type f \( -name 'libtinydocs_module.so' -o -name 'libtinydocs_module.dylib' \) -print -quit)"
if [[ -z "$module_artifact" || ! -f "$module_artifact" ]]; then
echo "the TinyDocs module artifact is missing" >&2
exit 1
fi
install -m 644 "$module_artifact" "$module_root/"

module_name="$(basename "$module_artifact")"
module_hash="$(shasum -a 256 "${module_root}/${module_name}" | awk '{print $1}')"
printf '"%s" = "%s"\n' "$module_name" "$module_hash" > "${module_root}/modules.toml"

install -m 644 LICENSE "${bundle_root}/LICENSE"
install -m 644 README.md "${bundle_root}/README.md"
install -m 644 docs/specs/tinybus-module.md "${bundle_root}/docs/tinydocs-module.md"
install -m 644 vendor/tinybus/docs/protocol.md "${bundle_root}/docs/tinybus-protocol.md"
cp -R vendor/tinybus/docs/modules "${bundle_root}/docs/tinybus-modules"

tar -C dist -czf "dist/${bundle_name}.tar.gz" "$bundle_name"
echo "archive=dist/${bundle_name}.tar.gz" >> "$GITHUB_OUTPUT"

- name: Upload native bundle
uses: actions/upload-artifact@v4
with:
name: tinydocs-${{ runner.os }}
path: ${{ steps.bundle.outputs.archive }}
if-no-files-found: error

github-release:
name: Create GitHub release
needs:
- publish
- native-bundles
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
pattern: '*'
path: release-assets
merge-multiple: true

- name: Create release and upload assets
env:
GH_TOKEN: ${{ github.token }}
RELEASE_TAG: ${{ needs.publish.outputs.tag }}
REPOSITORY: ${{ github.repository }}
run: >-
gh release create "$RELEASE_TAG" release-assets/*
--repo "$REPOSITORY"
--verify-tag
--title "$RELEASE_TAG"
--generate-notes
12 changes: 8 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ src/
└── test.rs # module-local unit tests
tests/ # integration tests against the public API only
examples/ # runnable, compiled-in-CI usage examples
crates/tinydocs-module/ # private TinyBus cdylib adapter
vendor/tinybus/ # pinned TinyBus source; optional until wired by a project
docs/
├── specs/ # behavior and architecture specifications
Expand Down Expand Up @@ -68,14 +69,15 @@ the crate-wide `Result<T>` from fallible public APIs.

## Build And Test

Run every command from the repository root. These four are the contract; CI
Run every command from the repository root. These five are the contract; CI
runs exactly them, so a green local run should mean a green CI run.

```sh
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo build --all-targets --all-features
cargo test --all-features
.github/scripts/check-file-coverage.sh 90 coverage.json
```

Supporting commands:
Expand All @@ -86,6 +88,8 @@ Supporting commands:
- `cargo doc --no-deps --all-features` — build the rustdoc CI also builds with
`RUSTDOCFLAGS="-D warnings"`.
- `cargo test --doc` — run doctests alone when editing documentation examples.
- `cargo install cargo-llvm-cov` — install the coverage tool required by the
per-file coverage gate.

Never skip, ignore, or delete a failing test to make a command pass. Fix the
root cause, or stop and report the blocker.
Expand Down Expand Up @@ -167,9 +171,9 @@ on every generated crate.
- Tests must be deterministic and independent of network, wall-clock time, and
execution order. Gate any live/network test behind a feature or an env var and
name it `live_*` so it is easy to exclude.
- Maintain at least 80% coverage of meaningful library behavior. Add or update
tests with every behavior change, and note any deliberately untested edge case
in the pull request description.
- Maintain at least 90% line coverage in every source file under `src/`. Add or
update tests with every behavior change, and note any deliberately untested
edge case in the pull request description.

Write the test first when fixing a bug: a failing test that reproduces the
report, then the fix that turns it green.
Expand Down
Loading
Loading