Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .config/mise/tasks/weaver/test/_default
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash
#MISE description="Run every policy and template package test, and compile the generated Go"
#MISE depends=["weaver:test:policies", "weaver:test:templates", "weaver:test:go"]
#MISE description="Run every policy and template package test, and validate generated Go and Rust"
#MISE depends=["weaver:test:policies", "weaver:test:templates", "weaver:test:go", "weaver:test:rust"]
4 changes: 4 additions & 0 deletions .config/mise/tasks/weaver/test/rust
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
#MISE description="Check that generated Rust is formatted, tested, and passes Clippy"
set -euo pipefail
exec ./buildscripts/check_rust_output.sh
1 change: 1 addition & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
- uses: jdx/mise-action@c2a87611a18de5b3828c5652fe268e992400cb5c # v4.3.0
- run: mise run weaver:test:templates
- run: mise run weaver:test:go
- run: mise run weaver:test:rust

markdown:
name: Markdown
Expand Down
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ Each template package includes:
Generated Go must pass `gofmt`, `go build`, and `go vet`, which
`mise run weaver:test:go` checks.

Generated Rust must pass formatting, consumer tests, and Clippy, which
`mise run weaver:test:rust` checks against the pinned OpenTelemetry Rust API
and SDK.

## Contribution guidelines

- Keep changes to the package being modified.
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ Run `mise tasks` to list every task and what it does.
Every test must pass before a pull request is merged. The `Checks` workflow
runs the same tasks.

For Rust packages, `mise run weaver:test:rust` compiles the expected output in
temporary crates and runs formatting, consumer tests, and Clippy. Put consumer
tests in a case's `test.rs`, importing the generated crate as
`generated_semconv`.

Keep test registries synthetic. Use neutral namespaces such as `myapp` and
`auth` rather than conventions from a real system.

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ is versioned and released from this repository, ready to be referenced by tag.

**The packages turn a semantic convention registry into code and keep that
registry fit for generation.** Templates generate typed telemetry helpers, such
as Go attribute values and metric instruments on the OpenTelemetry Go API.
as typed attribute values and signal helpers on the OpenTelemetry Go and
Rust APIs.
Policies run during `weaver registry check` and reject conventions a template
cannot render, before any code is written.

Expand All @@ -29,6 +30,9 @@ Templates live under [`templates`](templates) and policies under
[`policies`](policies). Each package directory has a README describing what it
does and the params it accepts.

- [Go code generation](templates/code/go/README.md)
- [Rust code generation](templates/code/rust/README.md)

## Using a package

Weaver accepts a Git repository as a template or policy location, in the form
Expand Down
115 changes: 115 additions & 0 deletions buildscripts/check_rust_output.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env bash

set -euo pipefail

OTEL_RUST_VERSION="${OTEL_RUST_VERSION:-0.33.0}"
WEAVER="${WEAVER:-weaver}"
ROOT="$(pwd)"
PACKAGE_DIR="${ROOT}/templates/code/rust"
TEMPLATES_ROOT="$(realpath "${PACKAGE_DIR}/../..")"

WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/weaver-rust.XXXXXX")"
trap 'rm -rf "${WORK_DIR}"' EXIT
export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-${WORK_DIR}/target}"

for test_dir in "${PACKAGE_DIR}"/tests/*/; do
test_name="$(basename "${test_dir}")"
[[ -f "${test_dir}expected-error.txt" ]] && continue
expected="${test_dir}expected"
if [[ ! -f "${expected}/mod.rs" ]]; then
echo " FAIL: ${test_name} is missing expected/mod.rs."
exit 1
fi
echo "-> Checking Rust [${test_name}] ..."

crate_dir="${WORK_DIR}/${test_name}"
mkdir -p "${crate_dir}/src"
cp -R "${expected}/." "${crate_dir}/src/"
mv "${crate_dir}/src/mod.rs" "${crate_dir}/src/lib.rs"
if [[ -f "${test_dir}test.rs" ]]; then
mkdir -p "${crate_dir}/tests"
cp "${test_dir}test.rs" "${crate_dir}/tests/attributes.rs"
fi
if [[ -d "${test_dir}tests" ]]; then
mkdir -p "${crate_dir}/tests"
cp -R "${test_dir}tests/." "${crate_dir}/tests/"
fi

cat >"${crate_dir}/Cargo.toml" <<EOF
[package]
name = "generated_semconv"
version = "0.0.0"
edition = "2021"
publish = false

[dependencies]
opentelemetry = { version = "=${OTEL_RUST_VERSION}", features = ["logs", "metrics", "trace"] }
opentelemetry_sdk = { version = "=${OTEL_RUST_VERSION}", features = ["logs", "metrics", "trace", "testing"] }
smallvec = { version = "=1.16.2", features = ["const_generics"] }
EOF

if [[ -f "${test_dir}dependency-params.yaml" ]]; then
dependency_dir="${crate_dir}/upstream"
mkdir -p "${dependency_dir}/src"
(
cd "${test_dir}"
NO_COLOR=1 "${WEAVER}" registry generate -r dependency --v2 --quiet \
--params dependency-params.yaml --templates="${TEMPLATES_ROOT}" \
code/rust "${dependency_dir}/src"
) || { echo " FAIL: ${test_name} could not generate its dependency."; exit 1; }
mv "${dependency_dir}/src/mod.rs" "${dependency_dir}/src/lib.rs"
cat >"${dependency_dir}/Cargo.toml" <<EOF
[package]
name = "upstream"
version = "0.0.0"
edition = "2021"
publish = false

[dependencies]
opentelemetry = "=${OTEL_RUST_VERSION}"
opentelemetry_sdk = "=${OTEL_RUST_VERSION}"
smallvec = { version = "=1.16.2", features = ["const_generics"] }
EOF
printf '\nupstream = { path = "upstream" }\n' >>"${crate_dir}/Cargo.toml"
(
cd "${dependency_dir}"
cargo fmt --all || exit 1
cargo fmt --all --check || exit 1
cargo clippy --all-targets -- -D warnings || exit 1
) || { echo " FAIL: ${test_name} dependency fails Rust validation."; exit 1; }
fi

(
cd "${crate_dir}"
cargo fmt --all || exit 1
cargo fmt --all --check || exit 1
if [[ "${test_name}" == allocations || -f "${test_dir}tests/allocations.rs" ]]; then
cargo test --release -- --nocapture || exit 1
else
cargo test || exit 1
fi
cargo clippy --all-targets -- -D warnings || exit 1
for invalid_consumer in "${test_dir}"compile-fail/*.rs; do
[[ -f "${invalid_consumer}" ]] || continue
expected_error="${invalid_consumer%.rs}.expected-error.txt"
if [[ ! -s "${expected_error}" ]]; then
echo " FAIL: ${invalid_consumer} is missing its expected diagnostic."
exit 1
fi
mkdir -p examples
cp "${invalid_consumer}" examples/invalid_consumer.rs
if cargo check --example invalid_consumer >diagnostics.txt 2>&1; then
echo " FAIL: ${invalid_consumer} compiled successfully."
exit 1
fi
if ! grep -Fq -f "${expected_error}" diagnostics.txt; then
cat diagnostics.txt
echo " FAIL: ${invalid_consumer} did not fail with its expected diagnostic."
exit 1
fi
rm examples/invalid_consumer.rs
echo " PASS: $(basename "${invalid_consumer}") rejects its invalid consumer."
done
) || { echo " FAIL: ${test_name} does not pass Rust validation."; exit 1; }
echo " PASS: ${test_name} formats, tests, and passes Clippy."
done
1 change: 1 addition & 0 deletions mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
go = "1.27.1"
jq = "1.8.1"
node = "24.21.0"
rust = { version = "1.99.0", profile = "minimal", components = ["rustfmt", "clippy"] }
"npm:prettier" = "3.9.9"
Loading
Loading