From 9de1d98e35d333d8a538330f71c1f020d16bea84 Mon Sep 17 00:00:00 2001 From: Will Killian Date: Mon, 18 May 2026 08:44:26 -0400 Subject: [PATCH 1/5] ci: add cli draft release assets Signed-off-by: Will Killian --- .github/workflows/ci.yaml | 37 +++++++++++++++++++++++++++++++++++ .github/workflows/ci_rust.yml | 27 ++++++++++++++++++++++--- crates/cli/Cargo.toml | 4 ++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 29890de1..099814dc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -321,6 +321,43 @@ jobs: id: deployment uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5 + release-cli-artifacts: + name: Release CLI Artifacts + needs: [prepare, ci_required] + if: ${{ needs.prepare.outputs.publish_packages == 'true' && needs.ci_required.result == 'success' }} + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: write + steps: + - name: Download CLI binary artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: cli-* + merge-multiple: true + path: release-assets/ + + - name: Verify CLI release assets + run: | + set -euo pipefail + shopt -s nullglob + assets=(release-assets/*) + if ((${#assets[@]} == 0)); then + echo "Error: no CLI release assets were downloaded" >&2 + exit 1 + fi + printf 'CLI release assets:\n' + printf ' %s\n' "${assets[@]}" + + - name: Upload CLI assets to draft GitHub Release + uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 + with: + draft: true + prerelease: ${{ contains(github.ref_name, '-beta.') || contains(github.ref_name, '-rc.') }} + overwrite_files: true + fail_on_unmatched_files: true + files: release-assets/* + publish-rust: name: Publish (crates.io) needs: [prepare, ci_required] diff --git a/.github/workflows/ci_rust.yml b/.github/workflows/ci_rust.yml index d275dfc1..fb956d52 100644 --- a/.github/workflows/ci_rust.yml +++ b/.github/workflows/ci_rust.yml @@ -167,14 +167,19 @@ jobs: include: - platform: linux-amd64 runner: ubuntu-latest + target: x86_64-unknown-linux-musl - platform: linux-arm64 runner: ubuntu-24.04-arm + target: aarch64-unknown-linux-musl - platform: macos-arm64 runner: macos-15 + target: aarch64-apple-darwin - platform: windows-amd64 runner: windows-2022 + target: x86_64-pc-windows-msvc - platform: windows-arm64 runner: windows-11-arm + target: aarch64-pc-windows-msvc steps: - name: Checkout @@ -188,6 +193,7 @@ jobs: with: cache: false toolchain: ${{ steps.ci-config.outputs.rust_version }} + target: ${{ matrix.target }} - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: @@ -197,27 +203,42 @@ jobs: cache-bin: false save-if: false + - name: Install musl tools + if: ${{ startsWith(matrix.target, 'x86_64-unknown-linux-musl') || startsWith(matrix.target, 'aarch64-unknown-linux-musl') }} + run: | + set -e + sudo apt-get update + sudo apt-get install -y musl-tools + - name: Build CLI release binary working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} run: | set -e - cargo build --release -p nemo-flow-cli + cargo build --release --target "${{ matrix.target }}" -p nemo-flow-cli - name: Stage CLI binary artifact working-directory: ${{ env.NEMO_FLOW_CI_WORKSPACE }} run: | set -euo pipefail + target="${{ matrix.target }}" + version="${{ github.ref_name }}" + if [ "${{ github.ref_type }}" != "tag" ]; then + version="dev-${GIT_COMMIT::8}" + fi binary="nemo-flow" + asset="nemo-flow-cli-${target}-${version}" if [ "${{ runner.os }}" = "Windows" ]; then binary="${binary}.exe" + asset="${asset}.exe" fi - source="${NEMO_FLOW_CI_WORKSPACE}/target/release/${binary}" + source="${NEMO_FLOW_CI_WORKSPACE}/target/${target}/release/${binary}" if [ ! -f "$source" ]; then echo "Error: expected CLI binary at ${source}" >&2 exit 1 fi + rm -rf "${NEMO_FLOW_CI_WORKSPACE_TMP}/cli" mkdir -p "${NEMO_FLOW_CI_WORKSPACE_TMP}/cli" - cp "$source" "${NEMO_FLOW_CI_WORKSPACE_TMP}/cli/${binary}" + cp "$source" "${NEMO_FLOW_CI_WORKSPACE_TMP}/cli/${asset}" - name: Upload CLI binary artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 14969c06..8bc95456 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -13,6 +13,10 @@ description = "Coding-agent gateway CLI for NeMo Flow observability." name = "nemo-flow" path = "src/main.rs" +[package.metadata.binstall] +pkg-url = "{ repo }/releases/download/{ version }/{ name }-{ target }-{ version }{ archive-suffix }" +pkg-fmt = "bin" + [lints] workspace = true From 371914567704141df5b09494845eadeccd6a6eb4 Mon Sep 17 00:00:00 2001 From: Will Killian Date: Mon, 18 May 2026 08:49:05 -0400 Subject: [PATCH 2/5] ci: add cli release checksums Signed-off-by: Will Killian --- .github/workflows/ci.yaml | 57 ++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 099814dc..465a23f0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -337,26 +337,69 @@ jobs: merge-multiple: true path: release-assets/ - - name: Verify CLI release assets + - name: Verify CLI release assets and generate checksums run: | set -euo pipefail + + version="${{ github.ref_name }}" + expected_assets=( + "nemo-flow-cli-x86_64-unknown-linux-musl-${version}" + "nemo-flow-cli-aarch64-unknown-linux-musl-${version}" + "nemo-flow-cli-aarch64-apple-darwin-${version}" + "nemo-flow-cli-x86_64-pc-windows-msvc-${version}.exe" + "nemo-flow-cli-aarch64-pc-windows-msvc-${version}.exe" + ) + + for asset in "${expected_assets[@]}"; do + if [ ! -f "release-assets/${asset}" ]; then + echo "Error: expected CLI release asset release-assets/${asset}" >&2 + exit 1 + fi + done + shopt -s nullglob - assets=(release-assets/*) - if ((${#assets[@]} == 0)); then - echo "Error: no CLI release assets were downloaded" >&2 + downloaded_assets=(release-assets/*) + if ((${#downloaded_assets[@]} != ${#expected_assets[@]})); then + echo "Error: unexpected CLI release asset set" >&2 + printf 'Downloaded assets:\n' >&2 + printf ' %s\n' "${downloaded_assets[@]}" >&2 exit 1 fi + + ( + cd release-assets + sha256sum "${expected_assets[@]}" > SHA256SUMS + sha256sum --check SHA256SUMS + + while read -r digest filename; do + printf '%s %s\n' "$digest" "$filename" > "${filename}.sha256" + done < SHA256SUMS + ) + printf 'CLI release assets:\n' - printf ' %s\n' "${assets[@]}" + printf ' release-assets/%s\n' "${expected_assets[@]}" + printf ' release-assets/%s.sha256\n' "${expected_assets[@]}" + printf ' release-assets/SHA256SUMS\n' - - name: Upload CLI assets to draft GitHub Release + - name: Upload CLI assets and checksums to draft GitHub Release uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 with: draft: true prerelease: ${{ contains(github.ref_name, '-beta.') || contains(github.ref_name, '-rc.') }} overwrite_files: true fail_on_unmatched_files: true - files: release-assets/* + files: | + release-assets/nemo-flow-cli-x86_64-unknown-linux-musl-${{ github.ref_name }} + release-assets/nemo-flow-cli-x86_64-unknown-linux-musl-${{ github.ref_name }}.sha256 + release-assets/nemo-flow-cli-aarch64-unknown-linux-musl-${{ github.ref_name }} + release-assets/nemo-flow-cli-aarch64-unknown-linux-musl-${{ github.ref_name }}.sha256 + release-assets/nemo-flow-cli-aarch64-apple-darwin-${{ github.ref_name }} + release-assets/nemo-flow-cli-aarch64-apple-darwin-${{ github.ref_name }}.sha256 + release-assets/nemo-flow-cli-x86_64-pc-windows-msvc-${{ github.ref_name }}.exe + release-assets/nemo-flow-cli-x86_64-pc-windows-msvc-${{ github.ref_name }}.exe.sha256 + release-assets/nemo-flow-cli-aarch64-pc-windows-msvc-${{ github.ref_name }}.exe + release-assets/nemo-flow-cli-aarch64-pc-windows-msvc-${{ github.ref_name }}.exe.sha256 + release-assets/SHA256SUMS publish-rust: name: Publish (crates.io) From 99f5b6ccc715b36aad58508f29d90d10f770a10d Mon Sep 17 00:00:00 2001 From: Will Killian Date: Mon, 18 May 2026 08:52:15 -0400 Subject: [PATCH 3/5] ci: simplify cli release checksum upload Signed-off-by: Will Killian --- .github/workflows/ci.yaml | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 465a23f0..3b9e4270 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -337,7 +337,7 @@ jobs: merge-multiple: true path: release-assets/ - - name: Verify CLI release assets and generate checksums + - name: Generate CLI release checksums run: | set -euo pipefail @@ -350,22 +350,6 @@ jobs: "nemo-flow-cli-aarch64-pc-windows-msvc-${version}.exe" ) - for asset in "${expected_assets[@]}"; do - if [ ! -f "release-assets/${asset}" ]; then - echo "Error: expected CLI release asset release-assets/${asset}" >&2 - exit 1 - fi - done - - shopt -s nullglob - downloaded_assets=(release-assets/*) - if ((${#downloaded_assets[@]} != ${#expected_assets[@]})); then - echo "Error: unexpected CLI release asset set" >&2 - printf 'Downloaded assets:\n' >&2 - printf ' %s\n' "${downloaded_assets[@]}" >&2 - exit 1 - fi - ( cd release-assets sha256sum "${expected_assets[@]}" > SHA256SUMS @@ -388,18 +372,7 @@ jobs: prerelease: ${{ contains(github.ref_name, '-beta.') || contains(github.ref_name, '-rc.') }} overwrite_files: true fail_on_unmatched_files: true - files: | - release-assets/nemo-flow-cli-x86_64-unknown-linux-musl-${{ github.ref_name }} - release-assets/nemo-flow-cli-x86_64-unknown-linux-musl-${{ github.ref_name }}.sha256 - release-assets/nemo-flow-cli-aarch64-unknown-linux-musl-${{ github.ref_name }} - release-assets/nemo-flow-cli-aarch64-unknown-linux-musl-${{ github.ref_name }}.sha256 - release-assets/nemo-flow-cli-aarch64-apple-darwin-${{ github.ref_name }} - release-assets/nemo-flow-cli-aarch64-apple-darwin-${{ github.ref_name }}.sha256 - release-assets/nemo-flow-cli-x86_64-pc-windows-msvc-${{ github.ref_name }}.exe - release-assets/nemo-flow-cli-x86_64-pc-windows-msvc-${{ github.ref_name }}.exe.sha256 - release-assets/nemo-flow-cli-aarch64-pc-windows-msvc-${{ github.ref_name }}.exe - release-assets/nemo-flow-cli-aarch64-pc-windows-msvc-${{ github.ref_name }}.exe.sha256 - release-assets/SHA256SUMS + files: release-assets/* publish-rust: name: Publish (crates.io) From 5d4323d41d0fd328670f07bc2a163888db457550 Mon Sep 17 00:00:00 2001 From: Will Killian Date: Mon, 18 May 2026 08:56:37 -0400 Subject: [PATCH 4/5] ci: derive cli checksums from downloaded assets Signed-off-by: Will Killian --- .github/workflows/ci.yaml | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3b9e4270..16e3ad57 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -341,29 +341,19 @@ jobs: run: | set -euo pipefail - version="${{ github.ref_name }}" - expected_assets=( - "nemo-flow-cli-x86_64-unknown-linux-musl-${version}" - "nemo-flow-cli-aarch64-unknown-linux-musl-${version}" - "nemo-flow-cli-aarch64-apple-darwin-${version}" - "nemo-flow-cli-x86_64-pc-windows-msvc-${version}.exe" - "nemo-flow-cli-aarch64-pc-windows-msvc-${version}.exe" - ) - ( cd release-assets - sha256sum "${expected_assets[@]}" > SHA256SUMS + cli_assets=(nemo-flow-cli-*) + sha256sum "${cli_assets[@]}" > SHA256SUMS sha256sum --check SHA256SUMS while read -r digest filename; do printf '%s %s\n' "$digest" "$filename" > "${filename}.sha256" done < SHA256SUMS - ) - printf 'CLI release assets:\n' - printf ' release-assets/%s\n' "${expected_assets[@]}" - printf ' release-assets/%s.sha256\n' "${expected_assets[@]}" - printf ' release-assets/SHA256SUMS\n' + printf 'CLI release assets:\n' + printf ' release-assets/%s\n' * + ) - name: Upload CLI assets and checksums to draft GitHub Release uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 From 1101688f59a8dc4d18455e8adc35ee694bacdb5b Mon Sep 17 00:00:00 2001 From: Will Killian Date: Mon, 18 May 2026 09:00:00 -0400 Subject: [PATCH 5/5] ci: use binary extension in binstall url Signed-off-by: Will Killian --- crates/cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 8bc95456..4316643a 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -14,7 +14,7 @@ name = "nemo-flow" path = "src/main.rs" [package.metadata.binstall] -pkg-url = "{ repo }/releases/download/{ version }/{ name }-{ target }-{ version }{ archive-suffix }" +pkg-url = "{ repo }/releases/download/{ version }/{ name }-{ target }-{ version }{ binary-ext }" pkg-fmt = "bin" [lints]