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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,11 @@ jobs:
python_api_wheels=(nemo_relay-*.whl)
cli_npm=(nemo-relay-bin-npm-*.tgz)
node_npm=(nemo-relay-node-npm-*.tgz)
expect_count 5 "CLI binary" "${cli_binaries[@]}"
expect_count 5 "CLI wheel" "${cli_wheels[@]}"
expect_count 5 "Python API wheel" "${python_api_wheels[@]}"
expect_count 6 "CLI npm" "${cli_npm[@]}"
expect_count 6 "Node npm" "${node_npm[@]}"
expect_count 7 "CLI binary" "${cli_binaries[@]}"
expect_count 7 "CLI wheel" "${cli_wheels[@]}"
expect_count 7 "Python API wheel" "${python_api_wheels[@]}"
expect_count 8 "CLI npm" "${cli_npm[@]}"
expect_count 8 "Node npm" "${node_npm[@]}"

mapfile -t distribution_assets < <(
find . -maxdepth 1 -type f \
Expand Down Expand Up @@ -517,7 +517,7 @@ jobs:
run: |
set -euo pipefail
version="${{ github.ref_name }}"
for pkg in node-packages/nemo-relay-node-npm-{linux-x64,linux-arm64,darwin-arm64,win32-x64,win32-arm64}-${version}.tgz; do
for pkg in node-packages/nemo-relay-node-npm-{linux-x64,linux-arm64,linux-x64-musl,linux-arm64-musl,darwin-arm64,win32-x64,win32-arm64}-${version}.tgz; do
name="$(tar xOf "$pkg" package/package.json | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).name')"
if npm view "${name}@${version}" version --registry https://registry.npmjs.org >/dev/null 2>&1; then
echo "${name} ${version} already exists on npm; skipping"
Expand All @@ -536,7 +536,7 @@ jobs:
run: |
set -euo pipefail
version="${{ github.ref_name }}"
for pkg in cli-packages/nemo-relay-bin-npm-{linux-x64,linux-arm64,darwin-arm64,win32-x64,win32-arm64}-${version}.tgz; do
for pkg in cli-packages/nemo-relay-bin-npm-{linux-x64,linux-arm64,linux-x64-musl,linux-arm64-musl,darwin-arm64,win32-x64,win32-arm64}-${version}.tgz; do
name="$(tar xOf "$pkg" package/package.json | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).name')"
if npm view "${name}@${version}" version --registry https://registry.npmjs.org >/dev/null 2>&1; then
echo "${name} ${version} already exists on npm; skipping"
Expand Down
145 changes: 145 additions & 0 deletions .github/workflows/ci_node.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,151 @@ jobs:
path: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/npm/*.tgz
if-no-files-found: error

PackageMusllinux:
name: Package (musllinux-${{ matrix.node_arch }})
needs: [Test]
if: ${{ inputs.run_package && !cancelled() && needs.Test.result == 'success' }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- node_arch: x64
platform: linux-musl-amd64
runner: ubuntu-latest
container_image: node:24-alpine3.22@sha256:191c9f0080fcbbc6547a85dc0ff7988072214a355aabdc1d2ec55a7dae5eea8a
- node_arch: arm64
platform: linux-musl-arm64
runner: ubuntu-24.04-arm
container_image: node:24-alpine3.22@sha256:191c9f0080fcbbc6547a85dc0ff7988072214a355aabdc1d2ec55a7dae5eea8a

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Load CI tool versions
id: ci-config
uses: ./.github/actions/load-ci-tool-versions

- name: Derive Node package version
working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }}
run: |
set -euo pipefail
version="$(node -e 'const fs = require("fs"); const pkg = JSON.parse(fs.readFileSync("crates/node/package.json", "utf8")); if (!pkg.version) { throw new Error("crates/node/package.json missing version field"); } console.log(pkg.version);')"
if [[ "${{ inputs.ref_type }}" == "tag" ]]; then
version="${{ inputs.ref_name }}"
else
version="${version}+${GITHUB_SHA::8}"
fi
printf 'NEMO_RELAY_NODE_PACKAGE_VERSION=%s\n' "$version" >> "$GITHUB_ENV"

- name: Build musllinux Node package
working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }}
run: |
set -euo pipefail
output_dir="${NEMO_RELAY_CI_WORKSPACE_TMP}/npm-musllinux"
mkdir -p "$output_dir"
docker run --rm \
--volume "${NEMO_RELAY_CI_WORKSPACE}:${NEMO_RELAY_CI_WORKSPACE}" \
--workdir "${NEMO_RELAY_CI_WORKSPACE}" \
--env NEMO_RELAY_RUST_VERSION="${{ steps.ci-config.outputs.rust_version }}" \
--env NEMO_RELAY_NODE_OUTPUT_DIR="$output_dir" \
--env NEMO_RELAY_NODE_VERSION="${NEMO_RELAY_NODE_PACKAGE_VERSION}" \
--env NEMO_RELAY_NODE_PLATFORM="${{ matrix.platform }}" \
"${{ matrix.container_image }}" \
sh -ceu '
apk add --no-cache build-base cmake curl python3
curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain "$NEMO_RELAY_RUST_VERSION"
export PATH="$HOME/.cargo/bin:$PATH"
node scripts/package_node_musllinux.mjs \
--version "$NEMO_RELAY_NODE_VERSION" \
--platform "$NEMO_RELAY_NODE_PLATFORM" \
--out "$NEMO_RELAY_NODE_OUTPUT_DIR"
'

- name: Upload musllinux Node npm package artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: node-npm-package-${{ matrix.platform }}
path: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/npm-musllinux/*.tgz
if-no-files-found: error

Comment thread
willkill07 marked this conversation as resolved.
PackageMusllinuxSmoke:
name: Package smoke (musllinux-${{ matrix.node_arch }})
needs: [Package, PackageMusllinux]
if: ${{ inputs.run_package && !cancelled() && needs.Package.result == 'success' && needs.PackageMusllinux.result == 'success' }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 30
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- node_arch: x64
platform: linux-musl-amd64
package_name: nemo-relay-node-linux-x64-musl
runner: ubuntu-latest
container_image: node:24-alpine3.22@sha256:191c9f0080fcbbc6547a85dc0ff7988072214a355aabdc1d2ec55a7dae5eea8a
- node_arch: arm64
platform: linux-musl-arm64
package_name: nemo-relay-node-linux-arm64-musl
runner: ubuntu-24.04-arm
container_image: node:24-alpine3.22@sha256:191c9f0080fcbbc6547a85dc0ff7988072214a355aabdc1d2ec55a7dae5eea8a

steps:
- name: Download Node metapackage artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: node-npm-package-linux-amd64
path: node-metapackage/

- name: Download matching musllinux Node native package artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: node-npm-package-${{ matrix.platform }}
path: node-native/

Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Install and load musllinux split Node package
run: |
set -euo pipefail
docker run --rm \
--volume "${{ github.workspace }}:${{ github.workspace }}" \
--workdir "${{ github.workspace }}" \
--env NEMO_RELAY_NODE_PACKAGE_NAME="${{ matrix.package_name }}" \
--env NEMO_RELAY_WORKSPACE="${{ github.workspace }}" \
"${{ matrix.container_image }}" \
sh -ceu '
smoke_dir="$(mktemp -d)"
trap "rm -rf $smoke_dir" EXIT
cd "$smoke_dir"
npm init --yes >/dev/null
metapackage="$(find "$NEMO_RELAY_WORKSPACE/node-metapackage" -name "nemo-relay-node-npm-[0-9]*.tgz" -print -quit)"
native="$(find "$NEMO_RELAY_WORKSPACE/node-native" -name "*.tgz" -print -quit)"
test -n "$metapackage"
test -n "$native"
npm install --ignore-scripts "$native" "$metapackage"
node -e "
const assert = require(\"node:assert/strict\");
const manifest = require(process.env.NEMO_RELAY_NODE_PACKAGE_NAME + \"/package.json\");
assert.deepEqual(manifest.libc, [\"musl\"]);
for (const entrypoint of [
\"nemo-relay-node\",
\"nemo-relay-node/typed\",
\"nemo-relay-node/plugin\",
\"nemo-relay-node/adaptive\",
\"nemo-relay-node/observability\",
\"nemo-relay-node/pii_redaction\",
\"nemo-relay-node/model_pricing\",
]) {
require(entrypoint);
}
"
'

PackageOpenClaw:
name: Package OpenClaw plugin
needs: [Test]
Expand Down
114 changes: 114 additions & 0 deletions .github/workflows/ci_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,120 @@ jobs:
working-directory: ${{ env.NEMO_RELAY_CI_WORKSPACE }}
run: uv cache prune --ci

Package-musllinux:
name: Package (musllinux-${{ matrix.architecture }})
needs: [Test]
if: ${{ inputs.run_package && !cancelled() && needs.Test.result == 'success' }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- architecture: x86_64
runner: ubuntu-latest
image: quay.io/pypa/musllinux_1_2_x86_64@sha256:7b54360b191356838f6e41d4b9820c69be4f3d8dc8e7bca26f2684d48e5c8633
- architecture: aarch64
runner: ubuntu-24.04-arm
image: quay.io/pypa/musllinux_1_2_aarch64@sha256:274a947b4d5d745b56b868b0d052641e0798a652e3e65755987edf60547d1268

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Load CI tool versions
id: ci-config
uses: ./.github/actions/load-ci-tool-versions

- name: Derive packaging tool versions
run: |
set -euo pipefail
maturin_version="$(awk '
$0 == "name = \"maturin\"" { found = 1; next }
found && /^version = / {
gsub(/"/, "", $3)
print $3
exit
}
' uv.lock)"
if [[ -z "$maturin_version" ]]; then
echo "Error: failed to read maturin version from uv.lock" >&2
exit 1
fi
version="$(sed -n 's/^version = "\(.*\)"$/\1/p' Cargo.toml | head -n1)"
if [[ -z "$version" ]]; then
echo "Error: failed to read workspace version from Cargo.toml" >&2
exit 1
fi
if [[ "${{ inputs.ref_type }}" == "tag" ]]; then
version="${{ inputs.ref_name }}"
else
version="${version}+${GITHUB_SHA::8}"
fi
{
printf 'NEMO_RELAY_MATURIN_VERSION=%s\n' "$maturin_version"
printf 'NEMO_RELAY_PACKAGE_VERSION=%s\n' "$version"
} >> "$GITHUB_ENV"

- name: Create packaging output directory
run: |
set -euo pipefail
mkdir -p "${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/musllinux-wheels"

- name: Build and smoke test musllinux wheel
env:
MUSLLINUX_IMAGE: ${{ matrix.image }}
MUSLLINUX_INTERPRETER: /opt/python/cp311-cp311/bin/python
MUSLLINUX_WHEEL_DIRECTORY: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/musllinux-wheels
NEMO_RELAY_RUST_VERSION: ${{ steps.ci-config.outputs.rust_version }}
run: |
set -euo pipefail
docker run --rm \
--volume "${{ env.NEMO_RELAY_CI_WORKSPACE }}:${{ env.NEMO_RELAY_CI_WORKSPACE }}" \
--workdir "${{ env.NEMO_RELAY_CI_WORKSPACE }}" \
--env MUSLLINUX_INTERPRETER \
--env MUSLLINUX_WHEEL_DIRECTORY \
--env NEMO_RELAY_MATURIN_VERSION \
--env NEMO_RELAY_PACKAGE_VERSION \
--env NEMO_RELAY_RUST_VERSION \
"$MUSLLINUX_IMAGE" \
/bin/sh -ec '
apk add --no-cache curl
curl --proto "=https" --tlsv1.2 --silent --show-error --fail https://sh.rustup.rs | \
sh -s -- -y --profile minimal --default-toolchain "$NEMO_RELAY_RUST_VERSION"
export PATH="$HOME/.cargo/bin:$PATH"
"$MUSLLINUX_INTERPRETER" -m pip install --no-cache-dir "maturin==$NEMO_RELAY_MATURIN_VERSION"
export PATH="$(dirname "$MUSLLINUX_INTERPRETER"):$PATH"
"$MUSLLINUX_INTERPRETER" scripts/package_python_musllinux.py \
--version "$NEMO_RELAY_PACKAGE_VERSION" \
--out "$MUSLLINUX_WHEEL_DIRECTORY" \
--interpreter "$MUSLLINUX_INTERPRETER"
wheel="$(find "$MUSLLINUX_WHEEL_DIRECTORY" -maxdepth 1 -name "*.whl" -print -quit)"
test -n "$wheel"
"$MUSLLINUX_INTERPRETER" -m venv /tmp/nemo-relay-musllinux-venv
/tmp/nemo-relay-musllinux-venv/bin/python -m pip install --no-deps "$wheel"
/tmp/nemo-relay-musllinux-venv/bin/python -c "import nemo_relay"
'

- name: Verify wheel platform tag
run: |
set -euo pipefail
shopt -s nullglob
wheels=("${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/musllinux-wheels"/*-cp311-abi3-musllinux_1_2_${{ matrix.architecture }}.whl)
if [[ "${#wheels[@]}" -ne 1 ]]; then
echo "Error: expected one cp311-abi3 musllinux wheel for ${{ matrix.architecture }}, found ${#wheels[@]}" >&2
exit 1
fi

- name: Upload wheel artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: wheel-musllinux-${{ matrix.architecture }}
path: ${{ env.NEMO_RELAY_CI_WORKSPACE_TMP }}/musllinux-wheels/*.whl
if-no-files-found: error

Package:
name: Package (${{ matrix.platform }})
needs: [Test]
Expand Down
Loading
Loading