name: Publish to crates.io on: workflow_call: workflow_dispatch: permissions: contents: read jobs: publish: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install dependencies run: | sudo apt-get update -y sudo apt-get install -y libpcap-dev libelf-dev zlib1g-dev clang llvm pkg-config - name: Set up Rust uses: dtolnay/rust-toolchain@stable # unpinned: maintained branch by Rust team member - name: Publish to crates.io env: CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} run: | # True if $crate@$VERSION is already on crates.io. `cargo search` does # fuzzy matching and prints `name = "version" # description`, so we # anchor on the exact `name = "version"` prefix. A bare `grep VERSION` # would false-match the version string appearing in a description, and # `--limit 1` alone isn't guaranteed to be the exact crate. is_published() { cargo search "$1" --limit 20 \ | grep -qF "$1 = \"$2\"" } # The workspace must be published in dependency order: rustnet-core # first, then the crates that depend on it, then the binary last. # Each crate's path deps also carry a version, so dependents resolve # against crates.io once their dependencies are indexed. for crate in rustnet-core rustnet-capture rustnet-host rustnet-monitor; do VERSION=$(cargo metadata --no-deps --format-version 1 \ | jq -r --arg n "$crate" '.packages[] | select(.name == $n) | .version') if is_published "$crate" "$VERSION"; then echo "⚠️ $crate@$VERSION already published to crates.io, skipping" continue fi echo "📦 Publishing $crate@$VERSION" cargo publish -p "$crate" # Wait for the new version to appear in the index before publishing # a dependent that requires it. if [ "$crate" != "rustnet-monitor" ]; then for _ in $(seq 1 30); do if is_published "$crate" "$VERSION"; then break fi echo "⏳ waiting for $crate@$VERSION to appear on crates.io..." sleep 10 done fi done