Unverified Commit 01a4b6d6 authored by Harrison Saturley-Hall's avatar Harrison Saturley-Hall Committed by GitHub
Browse files

chore: bump dynamo version numbers (#8191)

parent 6d4d0a61
......@@ -181,8 +181,6 @@ jobs:
ACCOUNT_ID="$(aws sts get-caller-identity --query Account --output text)"
ECR_HOSTNAME="${ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com"
ARCHITECTURES=("amd64" "arm64")
echo "========================================"
echo "Copying images from ECR to NGC (registry-to-registry)"
echo "Source commit SHA: ${COMMIT_SHA}"
......@@ -190,14 +188,11 @@ jobs:
echo "========================================"
copy_image() {
local SRC="$1" DST="$2" LABEL="$3" PLATFORM="${4:-}"
local PLATFORM_ARG=""
if [ -n "${PLATFORM}" ]; then
PLATFORM_ARG="--platform ${PLATFORM}"
fi
local SRC="$1" DST="$2" LABEL="$3"
echo "----------------------------------------"
echo "Copying: ${LABEL}"
if crane copy ${PLATFORM_ARG} "${SRC}" "${DST}"; then
# crane copy preserves multi-arch manifest lists by default (no --platform needed)
if crane copy "${SRC}" "${DST}"; then
echo " Copied: ${LABEL}"
SUCCESSFUL_COPIES+=("${LABEL}")
return 0
......@@ -208,36 +203,15 @@ jobs:
fi
}
create_manifest() {
local MANIFEST="$1" AMD64_IMG="$2" ARM64_IMG="$3" LABEL="$4"
echo "Creating manifest: ${MANIFEST}"
docker manifest create "${MANIFEST}" "${AMD64_IMG}" "${ARM64_IMG}" || true
if docker manifest push "${MANIFEST}"; then
echo " Created multi-arch: ${LABEL}"
SUCCESSFUL_COPIES+=("${LABEL} (multi-arch)")
else
echo " Failed to create multi-arch: ${LABEL}"
FAILED_COPIES+=("${LABEL} (multi-arch)")
fi
}
# ---- CUDA 12 runtime images (vllm and sglang) ----
echo ""
echo "=== CUDA 12 Runtime Images (vllm, sglang) ==="
CUDA12_FRAMEWORKS=("vllm" "sglang")
for FRAMEWORK in "${CUDA12_FRAMEWORKS[@]}"; do
NGC_NAME="${FRAMEWORK}-runtime"
for ARCH in "${ARCHITECTURES[@]}"; do
SOURCE="${ECR_HOSTNAME}/${REGISTRY_IMAGE}:${COMMIT_SHA}-${FRAMEWORK}-runtime-cuda12"
TARGET="${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-${ARCH}"
copy_image "${SOURCE}" "${TARGET}" "${NGC_NAME}:${NGC_VERSION_TAG}-${ARCH}" "linux/${ARCH}"
done
create_manifest \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}" \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-amd64" \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-arm64" \
"${NGC_NAME}:${NGC_VERSION_TAG}"
SOURCE="${ECR_HOSTNAME}/${REGISTRY_IMAGE}:${COMMIT_SHA}-${FRAMEWORK}-runtime-cuda12"
TARGET="${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}"
copy_image "${SOURCE}" "${TARGET}" "${NGC_NAME}:${NGC_VERSION_TAG}"
done
# ---- CUDA 13 runtime images (vllm, sglang, trtllm) ----
......@@ -251,17 +225,9 @@ jobs:
NGC_NAME="${FRAMEWORK}-runtime"
fi
for ARCH in "${ARCHITECTURES[@]}"; do
SOURCE="${ECR_HOSTNAME}/${REGISTRY_IMAGE}:${COMMIT_SHA}-${FRAMEWORK}-runtime-cuda13"
TARGET="${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13-${ARCH}"
copy_image "${SOURCE}" "${TARGET}" "${NGC_NAME}:${NGC_VERSION_TAG}-cuda13-${ARCH}" "linux/${ARCH}"
done
create_manifest \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13" \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13-amd64" \
"${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13-arm64" \
"${NGC_NAME}:${NGC_VERSION_TAG}-cuda13"
SOURCE="${ECR_HOSTNAME}/${REGISTRY_IMAGE}:${COMMIT_SHA}-${FRAMEWORK}-runtime-cuda13"
TARGET="${NGC_REGISTRY}/${NGC_ORG}/ai-dynamo/${NGC_NAME}:${NGC_VERSION_TAG}-cuda13"
copy_image "${SOURCE}" "${TARGET}" "${NGC_NAME}:${NGC_VERSION_TAG}-cuda13"
done
# ---- EFA runtime images (amd64 only, no multi-arch manifest needed) ----
......@@ -392,13 +358,13 @@ jobs:
echo "### Expected Images" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Runtime images (CUDA 12 - default):" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}\` (multi-arch)" >> $GITHUB_STEP_SUMMARY
echo "- \`sglang-runtime:${NGC_VERSION_TAG}\` (multi-arch)" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo "- \`sglang-runtime:${NGC_VERSION_TAG}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Runtime images (CUDA 13):" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}-cuda13\` (multi-arch)" >> $GITHUB_STEP_SUMMARY
echo "- \`sglang-runtime:${NGC_VERSION_TAG}-cuda13\` (multi-arch)" >> $GITHUB_STEP_SUMMARY
echo "- \`tensorrtllm-runtime:${NGC_VERSION_TAG}-cuda13\` (multi-arch)" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}-cuda13\`" >> $GITHUB_STEP_SUMMARY
echo "- \`sglang-runtime:${NGC_VERSION_TAG}-cuda13\`" >> $GITHUB_STEP_SUMMARY
echo "- \`tensorrtllm-runtime:${NGC_VERSION_TAG}-cuda13\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "EFA runtime images (amd64 only):" >> $GITHUB_STEP_SUMMARY
echo "- \`vllm-runtime:${NGC_VERSION_TAG}-efa\`" >> $GITHUB_STEP_SUMMARY
......
......@@ -2310,7 +2310,7 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "dynamo-bench"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"async-trait",
......@@ -2343,14 +2343,14 @@ dependencies = [
[[package]]
name = "dynamo-config"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
]
[[package]]
name = "dynamo-kv-router"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"async-trait",
......@@ -2383,7 +2383,7 @@ dependencies = [
[[package]]
name = "dynamo-llm"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"aho-corasick",
"aligned-vec",
......@@ -2483,7 +2483,7 @@ dependencies = [
[[package]]
name = "dynamo-memory"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"cudarc",
......@@ -2501,7 +2501,7 @@ dependencies = [
[[package]]
name = "dynamo-mocker"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"dashmap",
......@@ -2530,7 +2530,7 @@ dependencies = [
[[package]]
name = "dynamo-parsers"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"dynamo-protocols",
......@@ -2548,7 +2548,7 @@ dependencies = [
[[package]]
name = "dynamo-protocols"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"async-openai",
"derive_builder",
......@@ -2565,7 +2565,7 @@ dependencies = [
[[package]]
name = "dynamo-runtime"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"arc-swap",
......@@ -2640,7 +2640,7 @@ dependencies = [
[[package]]
name = "dynamo-tokens"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"bs58",
"bytemuck",
......@@ -4455,7 +4455,7 @@ dependencies = [
[[package]]
name = "kvbm-common"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"dynamo-tokens",
"serde",
......@@ -4463,7 +4463,7 @@ dependencies = [
[[package]]
name = "kvbm-config"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"dynamo-memory",
......@@ -4483,7 +4483,7 @@ dependencies = [
[[package]]
name = "kvbm-engine"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"async-nats",
......@@ -4523,7 +4523,7 @@ dependencies = [
[[package]]
name = "kvbm-kernels"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"clap 4.6.0",
"cudarc",
......@@ -4534,7 +4534,7 @@ dependencies = [
[[package]]
name = "kvbm-logical"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"async-stream",
......@@ -4564,7 +4564,7 @@ dependencies = [
[[package]]
name = "kvbm-physical"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"aligned-vec",
"anyhow",
......@@ -4620,7 +4620,7 @@ checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
[[package]]
name = "libdynamo_llm"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"async-once-cell",
......
......@@ -25,7 +25,7 @@ members = [
resolver = "3"
[workspace.package]
version = "1.0.0"
version = "1.1.0"
edition = "2024"
description = "Dynamo Inference Framework"
authors = ["NVIDIA Inc. <sw-dl-dynamo@nvidia.com>"]
......@@ -36,25 +36,25 @@ keywords = ["llm", "genai", "inference", "nvidia", "distributed"]
[workspace.dependencies]
# Local crates
dynamo-runtime = { path = "lib/runtime", version = "1.0.0" }
dynamo-llm = { path = "lib/llm", version = "1.0.0" }
dynamo-config = { path = "lib/config", version = "1.0.0" }
dynamo-tokens = { path = "lib/tokens", version = "1.0.0" }
dynamo-memory = { path = "lib/memory", version = "1.0.0" }
dynamo-mocker = { path = "lib/mocker", version = "1.0.0" }
dynamo-kv-router = { path = "lib/kv-router", version = "1.0.0", features = ["metrics", "runtime-protocols"] }
dynamo-protocols = { path = "lib/protocols", version = "1.0.0" }
dynamo-parsers = { path = "lib/parsers", version = "1.0.0" }
dynamo-runtime = { path = "lib/runtime", version = "1.1.0" }
dynamo-llm = { path = "lib/llm", version = "1.1.0" }
dynamo-config = { path = "lib/config", version = "1.1.0" }
dynamo-tokens = { path = "lib/tokens", version = "1.1.0" }
dynamo-memory = { path = "lib/memory", version = "1.1.0" }
dynamo-mocker = { path = "lib/mocker", version = "1.1.0" }
dynamo-kv-router = { path = "lib/kv-router", version = "1.1.0", features = ["metrics", "runtime-protocols"] }
dynamo-protocols = { path = "lib/protocols", version = "1.1.0" }
dynamo-parsers = { path = "lib/parsers", version = "1.1.0" }
fastokens = { version = "0.1.0" }
# kvbm
kvbm-common = { path = "lib/kvbm-common", version = "1.0.0" }
kvbm-config = { path = "lib/kvbm-config", version = "1.0.0" }
kvbm-engine = { path = "lib/kvbm-engine", version = "1.0.0" }
kvbm-kernels = { path = "lib/kvbm-kernels", version = "1.0.0" }
kvbm-logical = { path = "lib/kvbm-logical", version = "1.0.0" }
kvbm-physical = { path = "lib/kvbm-physical", version = "1.0.0" }
kvbm-common = { path = "lib/kvbm-common", version = "1.1.0" }
kvbm-config = { path = "lib/kvbm-config", version = "1.1.0" }
kvbm-engine = { path = "lib/kvbm-engine", version = "1.1.0" }
kvbm-kernels = { path = "lib/kvbm-kernels", version = "1.1.0" }
kvbm-logical = { path = "lib/kvbm-logical", version = "1.1.0" }
kvbm-physical = { path = "lib/kvbm-physical", version = "1.1.0" }
# velo
velo = { version = "0.1.0" }
......
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Generate a dependency CSV (and optional attribution markdown) for Go modules.
Extracts Go module dependencies from one or more Go module directories using
``go list -deps`` for names/versions and ``go-licenses report`` for SPDX
license identifiers. Falls back gracefully when ``go-licenses`` is not
installed. Optionally generates an attribution markdown file with full
license texts.
Usage:
python generate_go_deps.py -o go_deps.csv
python generate_go_deps.py --attributions ATTRIBUTIONS-Go.md
python generate_go_deps.py --module-dirs deploy/operator -o operator_deps.csv -v
"""
import argparse
import csv
import io
import json
import logging
import re
import subprocess
import sys
from pathlib import Path
_SCRIPT_DIR = Path(__file__).resolve().parent
_REPO_ROOT = _SCRIPT_DIR.parent.parent
log = logging.getLogger(__name__)
FIELDNAMES = ["dependency_type", "package_name", "version", "spdx_license", "repo_url"]
DEFAULT_MODULE_DIRS = [
"deploy/operator",
"deploy/snapshot",
]
DEFAULT_IGNORE_PREFIXES = "github.com/ai-dynamo/dynamo"
# Transitive test/indirect deps that go-licenses requires to be fetched
# before it can scan certain modules. Keyed by module directory (relative to
# repo root). See deploy/snapshot/deps.md for background.
_PREFETCH_DEPS: dict[str, list[str]] = {
"deploy/snapshot": [
"github.com/opencontainers/runtime-spec/schema@v1.2.0",
"github.com/evanphx/json-patch",
"github.com/jessevdk/go-flags",
],
}
_LICENSE_NAMES = [
"LICENSE",
"LICENSE.md",
"LICENSE.txt",
"LICENSE-MIT",
"LICENSE-APACHE",
"LICENCE",
"LICENCE.md",
"LICENCE.txt",
"COPYING",
"COPYING.md",
]
_ATTRIBUTION_PREAMBLE = """\
<!--
SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->
# Third-Party Software Attributions
This project uses the following third-party libraries. Each library is \
open-source and licensed under the terms indicated below.
This file is automatically generated. Please do not edit it directly.
## Dependencies
"""
# Well-known Go module path -> repository URL mappings
_WELLKNOWN_REPOS: dict[str, str] = {
"google.golang.org/grpc": "https://github.com/grpc/grpc-go",
"google.golang.org/protobuf": "https://github.com/protocolbuffers/protobuf-go",
"google.golang.org/genproto": "https://github.com/googleapis/go-genproto",
"google.golang.org/api": "https://github.com/googleapis/google-api-go-client",
"google.golang.org/appengine": "https://github.com/golang/appengine",
"cloud.google.com/go": "https://github.com/googleapis/google-cloud-go",
}
# Prefix-based mappings (checked in order)
_PREFIX_REPOS: list[tuple[str, str]] = [
("golang.org/x/", "https://github.com/golang/"),
("k8s.io/", "https://github.com/kubernetes/"),
("sigs.k8s.io/", "https://github.com/kubernetes-sigs/"),
("go.uber.org/", "https://github.com/uber-go/"),
("go.opentelemetry.io/", "https://github.com/open-telemetry/"),
("go.etcd.io/", "https://github.com/etcd-io/"),
]
def _parse_json_stream(text: str) -> list[dict]:
"""Parse a stream of concatenated JSON objects (as emitted by ``go list -json``)."""
decoder = json.JSONDecoder()
results = []
idx = 0
length = len(text)
while idx < length:
# Skip whitespace
while idx < length and text[idx] in " \t\n\r":
idx += 1
if idx >= length:
break
obj, end = decoder.raw_decode(text, idx)
results.append(obj)
idx = end
return results
def prefetch_deps(module_dir: Path, go_cmd: str, deps: list[str]) -> None:
"""Run ``go get`` to fetch transitive deps that go-licenses needs present."""
cmd = [go_cmd, "get"] + deps
log.debug("Pre-fetching in %s: %s", module_dir, " ".join(cmd))
result = subprocess.run(
cmd, capture_output=True, text=True, timeout=300, cwd=str(module_dir)
)
if result.returncode != 0:
log.warning(
"go get pre-fetch failed (exit %d) in %s: %s",
result.returncode,
module_dir,
result.stderr.strip(),
)
else:
log.info("Pre-fetched %d transitive deps in %s", len(deps), module_dir)
def get_go_modules(
module_dir: Path, go_cmd: str, packages: list[str]
) -> dict[str, str]:
"""Return a {module_path: version} map for modules actually imported by *packages*.
Uses ``go list -deps`` to walk the transitive import graph so that modules
which are in the module graph (``go list -m all``) but never imported are
excluded.
"""
cmd = [
go_cmd,
"list",
"-deps",
"-f",
"{{if .Module}}{{.Module.Path}}\t{{.Module.Version}}{{end}}",
] + packages
log.debug("Running in %s: %s ...", module_dir, " ".join(cmd[:6]))
result = subprocess.run(
cmd, capture_output=True, text=True, timeout=300, cwd=str(module_dir)
)
if result.returncode != 0:
log.error(
"go list -deps failed (exit %d) in %s: %s",
result.returncode,
module_dir,
result.stderr,
)
raise RuntimeError(f"go list -deps failed in {module_dir}: {result.stderr}")
modules: dict[str, str] = {}
for line in result.stdout.strip().splitlines():
if not line or "\t" not in line:
continue
path, version = line.split("\t", 1)
if path and version:
modules[path] = version
return modules
def resolve_go_packages(module_dir: Path, go_cmd: str) -> list[str]:
"""Resolve the list of Go packages in *module_dir*.
Finds subdirectories containing ``.go`` files and runs ``go list`` on them,
skipping stale/non-module directories (e.g. ``srcs/``, ``vendor/``).
"""
go_dirs: set[str] = set()
for go_file in module_dir.rglob("*.go"):
rel = go_file.parent.relative_to(module_dir)
parts = rel.parts
if parts and any(
p in ("vendor", "srcs", "testdata") or "@" in p for p in parts
):
continue
go_dirs.add(str(rel))
if go_dirs:
top_dirs = {d.split("/")[0] if "/" in d else d for d in go_dirs if d != "."}
if "." in go_dirs:
top_dirs.add(".")
patterns = [f"./{d}/..." for d in sorted(top_dirs)] if top_dirs else ["./..."]
else:
patterns = ["./..."]
list_result = subprocess.run(
[go_cmd, "list"] + patterns,
capture_output=True,
text=True,
timeout=300,
cwd=str(module_dir),
)
if list_result.returncode != 0:
log.warning("go list failed in %s: %s", module_dir, list_result.stderr.strip())
return patterns
packages = [p for p in list_result.stdout.strip().splitlines() if p]
if not packages:
return patterns
log.debug("Resolved %d packages in %s", len(packages), module_dir)
return packages
def get_go_licenses(
module_dir: Path, go_licenses_cmd: str, ignore_prefix: str, packages: list[str]
) -> dict[str, tuple[str, str]]:
"""Run ``go-licenses report`` and return a {package_path: (license_url, spdx)} map."""
cmd = [go_licenses_cmd, "report"] + packages
if ignore_prefix:
cmd.extend(["--ignore", ignore_prefix])
log.debug("Running in %s: %s", module_dir, " ".join(cmd[:5]) + " ...")
result = subprocess.run(
cmd, capture_output=True, text=True, timeout=300, cwd=str(module_dir)
)
if result.returncode != 0:
log.warning(
"go-licenses failed (exit %d) in %s: %s",
result.returncode,
module_dir,
result.stderr.strip(),
)
raise RuntimeError(f"go-licenses failed in {module_dir}")
licenses = {}
reader = csv.reader(io.StringIO(result.stdout))
for row in reader:
if len(row) < 3:
continue
pkg_path, license_url, spdx = row[0], row[1], row[2]
licenses[pkg_path] = (license_url, spdx)
return licenses
def find_license_for_module(
module_path: str, licenses: dict[str, tuple[str, str]]
) -> tuple[str, str]:
"""Find the SPDX license and license URL for a module using longest prefix match.
Returns (license_url, spdx_license) or ("", "UNKNOWN") if not found.
"""
best_match = ""
best_value = ("", "UNKNOWN")
for pkg_path, (license_url, spdx) in licenses.items():
# Check if the package path starts with the module path
if pkg_path == module_path or pkg_path.startswith(module_path + "/"):
if len(module_path) > len(best_match):
best_match = module_path
best_value = (license_url, spdx)
# Also check if the module path starts with the package path
# (for cases where go-licenses reports a parent package)
elif module_path.startswith(pkg_path + "/") or module_path == pkg_path:
if len(pkg_path) > len(best_match):
best_match = pkg_path
best_value = (license_url, spdx)
return best_value
def _strip_version_suffix(module_path: str) -> str:
"""Strip Go major version suffix like /v2, /v3, etc."""
return re.sub(r"/v\d+$", "", module_path)
def derive_repo_url(module_path: str, license_url: str = "") -> str:
"""Derive a repository URL from a Go module path and optional license URL.
Tries to extract the repo URL from the license URL first (most reliable),
then falls back to heuristics based on the module path.
"""
# Try to extract repo URL from license URL (e.g., https://github.com/X/Y/blob/vN/LICENSE)
if license_url:
m = re.match(r"(https://github\.com/[^/]+/[^/]+)", license_url)
if m:
return m.group(1)
m = re.match(r"(https://gitlab\.com/[^/]+/[^/]+)", license_url)
if m:
return m.group(1)
clean_path = _strip_version_suffix(module_path)
# Check well-known exact mappings
for prefix, url in _WELLKNOWN_REPOS.items():
if clean_path == prefix or clean_path.startswith(prefix + "/"):
return url
# Check prefix-based mappings
for prefix, url_base in _PREFIX_REPOS:
if clean_path.startswith(prefix):
# Extract the first path component after the prefix
remainder = clean_path[len(prefix) :]
name = remainder.split("/")[0]
return url_base + name
# github.com/X/Y/... -> https://github.com/X/Y
if clean_path.startswith("github.com/"):
parts = clean_path.split("/")
if len(parts) >= 3:
return f"https://github.com/{parts[1]}/{parts[2]}"
# gitlab.com/X/Y/... -> https://gitlab.com/X/Y
if clean_path.startswith("gitlab.com/"):
parts = clean_path.split("/")
if len(parts) >= 3:
return f"https://gitlab.com/{parts[1]}/{parts[2]}"
# gopkg.in/X.vN -> https://github.com/go-X/X (single element)
# gopkg.in/USER/X.vN -> https://github.com/USER/X (two elements)
if clean_path.startswith("gopkg.in/"):
remainder = clean_path[len("gopkg.in/") :]
# Strip .vN suffix
remainder = re.sub(r"\.v\d+$", "", remainder)
parts = remainder.split("/")
if len(parts) == 1:
return f"https://github.com/go-{parts[0]}/{parts[0]}"
elif len(parts) >= 2:
return f"https://github.com/{parts[0]}/{parts[1]}"
# Fallback: link to pkg.go.dev
return f"https://pkg.go.dev/{module_path}"
def deduplicate(entries: list[dict[str, str]]) -> list[dict[str, str]]:
"""Deduplicate entries by (package_name, version)."""
seen: dict[tuple[str, str], dict[str, str]] = {}
for entry in entries:
key = (entry["package_name"], entry["version"])
if key not in seen:
seen[key] = entry
return list(seen.values())
def get_module_cache_dirs(module_dir: Path, go_cmd: str) -> dict[str, str]:
"""Run ``go list -m -json all`` and return a {module_path: dir} map.
Only includes modules that have a local ``Dir`` (i.e. are cached).
"""
cmd = [go_cmd, "list", "-m", "-json", "all"]
log.debug("Fetching module cache dirs in %s ...", module_dir)
result = subprocess.run(
cmd, capture_output=True, text=True, timeout=300, cwd=str(module_dir)
)
if result.returncode != 0:
log.warning("go list -m -json all failed: %s", result.stderr.strip())
return {}
dirs: dict[str, str] = {}
for obj in _parse_json_stream(result.stdout):
path = obj.get("Path", "")
mod_dir = obj.get("Dir", "")
if path and mod_dir and not obj.get("Main"):
dirs[path] = mod_dir
return dirs
def _find_license_text(directory: Path) -> str:
"""Find and read a license file in *directory*."""
for name in _LICENSE_NAMES:
path = directory / name
if path.is_file():
return path.read_text(errors="replace").rstrip()
return ""
def write_attributions_md(
packages: list[dict[str, str]],
output_path: str,
module_dirs_map: dict[str, str],
) -> None:
"""Write a markdown attribution file following the ATTRIBUTIONS-Go.md style."""
sorted_packages = sorted(
packages, key=lambda p: (p["package_name"].lower(), p["version"])
)
lines = [_ATTRIBUTION_PREAMBLE]
found = 0
for pkg in sorted_packages:
mod_dir = module_dirs_map.get(pkg["package_name"], "")
license_text = _find_license_text(Path(mod_dir)) if mod_dir else ""
lines.append(f"### {pkg['package_name']}")
lines.append("")
lines.append(f"License Identifier: {pkg['spdx_license']}")
lines.append("License Text:")
if license_text:
lines.append(f"```\n{license_text}\n```")
found += 1
else:
lines.append("```\nLicense text not available locally.\n```")
lines.append("")
with open(output_path, "w") as f:
f.write("\n".join(lines) + "\n")
log.info(
"Wrote attribution markdown to %s (%d/%d with license text)",
output_path,
found,
len(sorted_packages),
)
def write_csv(packages: list[dict[str, str]], output_path: str | None) -> None:
"""Write packages to CSV, sorted by package_name."""
sorted_packages = sorted(packages, key=lambda p: p["package_name"])
if output_path:
with open(output_path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
writer.writeheader()
writer.writerows(sorted_packages)
log.info("Wrote %d entries to %s", len(sorted_packages), output_path)
else:
writer = csv.DictWriter(sys.stdout, fieldnames=FIELDNAMES)
writer.writeheader()
writer.writerows(sorted_packages)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Generate a dependency CSV for Go modules",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s -o go_deps.csv
%(prog)s --module-dirs deploy/operator -o operator_deps.csv
%(prog)s -v
""",
)
parser.add_argument(
"--output",
"-o",
help="Output CSV file path (default: stdout)",
)
parser.add_argument(
"--attributions",
help="Output attribution markdown file path (e.g. ATTRIBUTIONS-Go.md)",
)
parser.add_argument(
"--module-dirs",
default=",".join(DEFAULT_MODULE_DIRS),
help=(
"Comma-separated Go module directories relative to repo root "
f"(default: {','.join(DEFAULT_MODULE_DIRS)})"
),
)
parser.add_argument(
"--go-cmd",
default="go",
help="Path to go binary (default: go)",
)
parser.add_argument(
"--go-licenses-cmd",
default="go-licenses",
help="Path to go-licenses binary (default: go-licenses)",
)
parser.add_argument(
"--ignore-prefixes",
default=DEFAULT_IGNORE_PREFIXES,
help=(
"Comma-separated module prefixes to exclude from license scan "
f"(default: {DEFAULT_IGNORE_PREFIXES})"
),
)
parser.add_argument(
"--verbose",
"-v",
action="store_true",
help="Enable verbose logging",
)
return parser.parse_args()
def main() -> None:
args = parse_args()
logging.basicConfig(
level=logging.DEBUG if args.verbose else logging.INFO,
format="%(levelname)s: %(message)s",
stream=sys.stderr,
)
module_dirs = [d.strip() for d in args.module_dirs.split(",") if d.strip()]
ignore_prefix = args.ignore_prefixes.strip()
all_entries: list[dict[str, str]] = []
for rel_dir in module_dirs:
abs_dir = _REPO_ROOT / rel_dir
if not (abs_dir / "go.mod").is_file():
log.error("go.mod not found in %s", abs_dir)
sys.exit(1)
# Resolve packages (skips stale dirs like srcs/)
packages = resolve_go_packages(abs_dir, args.go_cmd)
# Pre-fetch transitive deps that go-licenses requires
prefetch = _PREFETCH_DEPS.get(rel_dir, [])
if prefetch:
prefetch_deps(abs_dir, args.go_cmd, prefetch)
# Pass 1: get only transitively-imported modules
log.info("Listing imported modules in %s ...", rel_dir)
try:
modules = get_go_modules(abs_dir, args.go_cmd, packages)
except (RuntimeError, FileNotFoundError) as exc:
log.error("Failed to list modules in %s: %s", rel_dir, exc)
sys.exit(1)
log.info("Found %d imported modules in %s", len(modules), rel_dir)
# Pass 2: get license info via go-licenses
licenses: dict[str, tuple[str, str]] = {}
try:
licenses = get_go_licenses(
abs_dir, args.go_licenses_cmd, ignore_prefix, packages
)
log.info("Found %d license entries in %s", len(licenses), rel_dir)
except FileNotFoundError:
log.warning(
"go-licenses not found on PATH. Install with: "
"go install github.com/google/go-licenses@v1.6.0"
)
log.warning("License info will be UNKNOWN for all modules.")
except RuntimeError:
log.warning(
"go-licenses failed for %s, license info will be UNKNOWN.", rel_dir
)
# Merge: build entries for each module
for mod_path, version in modules.items():
license_url, spdx = find_license_for_module(mod_path, licenses)
repo_url = derive_repo_url(mod_path, license_url)
all_entries.append(
{
"dependency_type": "go",
"package_name": mod_path,
"version": version,
"spdx_license": spdx,
"repo_url": repo_url,
}
)
deduplicated = deduplicate(all_entries)
log.info("Total unique Go dependencies: %d", len(deduplicated))
if args.output or not args.attributions:
write_csv(deduplicated, args.output)
if args.attributions:
# Fetch local cache dirs from each Go module directory and merge.
unique_mods = {e["package_name"] for e in deduplicated}
module_dirs_map: dict[str, str] = {}
for rel_dir in module_dirs:
abs_dir = _REPO_ROOT / rel_dir
partial = get_module_cache_dirs(abs_dir, args.go_cmd)
# Only keep modules we actually need
for mod_path, mod_dir in partial.items():
if mod_path in unique_mods and mod_path not in module_dirs_map:
module_dirs_map[mod_path] = mod_dir
log.info(
"Resolved %d/%d module cache dirs", len(module_dirs_map), len(unique_mods)
)
write_attributions_md(deduplicated, args.attributions, module_dirs_map)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
"""Generate a dependency CSV (and optional attribution markdown) for Rust crates.
Extracts external Rust dependencies from one or more Cargo workspaces using
``cargo metadata`` and writes a CSV with dependency type, package name,
version, SPDX license identifier, and repository URL. Optionally generates
an attribution markdown file with full license texts.
Usage:
python generate_rust_deps.py -o rust_deps.csv
python generate_rust_deps.py --attributions ATTRIBUTIONS-Rust.md
python generate_rust_deps.py -o rust_deps.csv --attributions attr.md -v
"""
import argparse
import csv
import json
import logging
import re
import subprocess
import sys
from pathlib import Path
_SCRIPT_DIR = Path(__file__).resolve().parent
_REPO_ROOT = _SCRIPT_DIR.parent.parent
log = logging.getLogger(__name__)
FIELDNAMES = ["dependency_type", "package_name", "version", "spdx_license", "repo_url"]
DEFAULT_MANIFEST_PATHS = [
"Cargo.toml",
"lib/bindings/python/Cargo.toml",
"lib/bindings/kvbm/Cargo.toml",
]
_LICENSE_NAMES = [
"LICENSE",
"LICENSE.md",
"LICENSE.txt",
"LICENSE-MIT",
"LICENSE-APACHE",
"LICENCE",
"LICENCE.md",
"LICENCE.txt",
"COPYING",
"COPYING.md",
]
_ATTRIBUTION_PREAMBLE = """\
<!--
SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->
# Third-Party Software Attributions
This project uses the following third-party libraries. Each library is \
open-source and licensed under the terms indicated below.
This file is automatically generated. Please do not edit it directly.
"""
def get_cargo_metadata(manifest_path: Path, cargo_cmd: str) -> dict:
"""Run ``cargo metadata`` and return the parsed JSON."""
cmd = [
cargo_cmd,
"metadata",
"--format-version",
"1",
"--locked",
"--manifest-path",
str(manifest_path),
]
log.debug("Running: %s", " ".join(cmd))
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
if result.returncode != 0:
log.error(
"cargo metadata failed (exit %d) for %s: %s",
result.returncode,
manifest_path,
result.stderr,
)
raise RuntimeError(
f"cargo metadata failed for {manifest_path}: {result.stderr}"
)
return json.loads(result.stdout)
def extract_external_deps(metadata: dict) -> list[dict[str, str]]:
"""Extract external (non-workspace, non-local) dependencies from cargo metadata."""
workspace_member_ids = set(metadata.get("workspace_members", []))
packages = []
for pkg in metadata.get("packages", []):
# Skip workspace members (local crates)
if pkg["id"] in workspace_member_ids:
continue
# Skip path-only dependencies (local crates outside the workspace)
if pkg.get("source") is None:
continue
repo_url = pkg.get("repository") or ""
if not repo_url:
repo_url = f"https://crates.io/crates/{pkg['name']}"
packages.append(
{
"dependency_type": "rust",
"package_name": pkg["name"],
"version": pkg["version"],
"spdx_license": pkg.get("license") or "UNKNOWN",
"repo_url": repo_url,
"manifest_path": pkg.get("manifest_path", ""),
}
)
return packages
def deduplicate(entries: list[dict[str, str]]) -> list[dict[str, str]]:
"""Deduplicate entries by (package_name, version)."""
seen: dict[tuple[str, str], dict[str, str]] = {}
for entry in entries:
key = (entry["package_name"], entry["version"])
if key not in seen:
seen[key] = entry
return list(seen.values())
def _find_license_text(directory: Path) -> str:
"""Find and read a license file in *directory*."""
for name in _LICENSE_NAMES:
path = directory / name
if path.is_file():
return path.read_text(errors="replace").rstrip()
return ""
def _raw_license_url(repo_url: str, license_filename: str = "LICENSE") -> str:
"""Convert a GitHub/GitLab repo URL to a raw license URL for display."""
m = re.match(r"https://github\.com/([^/]+/[^/]+)", repo_url)
if m:
return f"https://raw.githubusercontent.com/{m.group(1)}/HEAD/{license_filename}"
return repo_url
def write_attributions_md(packages: list[dict[str, str]], output_path: str) -> None:
"""Write a markdown attribution file following the ATTRIBUTIONS-Rust.md style."""
sorted_packages = sorted(
packages, key=lambda p: (p["package_name"].lower(), p["version"])
)
lines = [_ATTRIBUTION_PREAMBLE]
found = 0
for pkg in sorted_packages:
manifest = pkg.get("manifest_path", "")
license_text = ""
license_filename = "LICENSE"
if manifest:
pkg_dir = Path(manifest).parent
for name in _LICENSE_NAMES:
path = pkg_dir / name
if path.is_file():
license_text = path.read_text(errors="replace").rstrip()
license_filename = name
break
raw_url = _raw_license_url(pkg["repo_url"], license_filename)
lines.append(f"\n## {pkg['package_name']} - {pkg['version']}")
lines.append(f"**Repository URL**: {pkg['repo_url']}")
lines.append(f"**License Type(s)**: {pkg['spdx_license']}")
lines.append(f"### License: {raw_url}")
if license_text:
lines.append(f"```\n{license_text}\n```")
found += 1
else:
lines.append("```\nLicense text not available locally.\n```")
with open(output_path, "w") as f:
f.write("\n".join(lines) + "\n")
log.info(
"Wrote attribution markdown to %s (%d/%d with license text)",
output_path,
found,
len(sorted_packages),
)
def write_csv(packages: list[dict[str, str]], output_path: str | None) -> None:
"""Write packages to CSV, sorted by package_name."""
sorted_packages = sorted(packages, key=lambda p: p["package_name"])
if output_path:
with open(output_path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=FIELDNAMES, extrasaction="ignore")
writer.writeheader()
writer.writerows(sorted_packages)
log.info("Wrote %d entries to %s", len(sorted_packages), output_path)
else:
writer = csv.DictWriter(
sys.stdout, fieldnames=FIELDNAMES, extrasaction="ignore"
)
writer.writeheader()
writer.writerows(sorted_packages)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Generate a dependency CSV for Rust crates in the workspace",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s -o rust_deps.csv
%(prog)s --manifest-paths Cargo.toml -o rust_deps.csv
%(prog)s -v
""",
)
parser.add_argument(
"--output",
"-o",
help="Output CSV file path (default: stdout)",
)
parser.add_argument(
"--attributions",
help="Output attribution markdown file path (e.g. ATTRIBUTIONS-Rust.md)",
)
parser.add_argument(
"--manifest-paths",
default=",".join(DEFAULT_MANIFEST_PATHS),
help=(
"Comma-separated Cargo.toml paths relative to repo root "
f"(default: {','.join(DEFAULT_MANIFEST_PATHS)})"
),
)
parser.add_argument(
"--cargo-cmd",
default="cargo",
help="Path to cargo binary (default: cargo)",
)
parser.add_argument(
"--verbose",
"-v",
action="store_true",
help="Enable verbose logging",
)
return parser.parse_args()
def main() -> None:
args = parse_args()
logging.basicConfig(
level=logging.DEBUG if args.verbose else logging.INFO,
format="%(levelname)s: %(message)s",
stream=sys.stderr,
)
manifest_paths = [p.strip() for p in args.manifest_paths.split(",") if p.strip()]
all_entries: list[dict[str, str]] = []
for rel_path in manifest_paths:
abs_path = _REPO_ROOT / rel_path
if not abs_path.is_file():
log.warning("Manifest not found, skipping: %s", abs_path)
continue
log.info("Scanning %s ...", rel_path)
try:
metadata = get_cargo_metadata(abs_path, args.cargo_cmd)
except (RuntimeError, FileNotFoundError) as exc:
log.error("Failed to get metadata for %s: %s", rel_path, exc)
sys.exit(1)
entries = extract_external_deps(metadata)
log.info("Found %d external deps in %s", len(entries), rel_path)
all_entries.extend(entries)
deduplicated = deduplicate(all_entries)
log.info("Total unique Rust dependencies: %d", len(deduplicated))
if args.output or not args.attributions:
write_csv(deduplicated, args.output)
if args.attributions:
write_attributions_md(deduplicated, args.attributions)
if __name__ == "__main__":
main()
......@@ -19,11 +19,11 @@ maintainers:
url: https://www.nvidia.com
description: A Helm chart for NVIDIA Dynamo Platform.
type: application
version: 1.0.0
version: 1.1.0
home: https://nvidia.com
dependencies:
- name: dynamo-operator
version: 1.0.0
version: 1.1.0
repository: file://components/operator
condition: dynamo-operator.enabled
- name: nats
......
......@@ -19,7 +19,7 @@ limitations under the License.
A Helm chart for NVIDIA Dynamo Platform.
![Version: 1.0.0](https://img.shields.io/badge/Version-1.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)
![Version: 1.1.0](https://img.shields.io/badge/Version-1.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)
## 🚀 Overview
......@@ -97,7 +97,7 @@ The chart includes built-in validation to prevent all operator conflicts:
| Repository | Name | Version |
|------------|------|---------|
| file://components/operator | dynamo-operator | 1.0.0 |
| file://components/operator | dynamo-operator | 1.1.0 |
| https://charts.bitnami.com/bitnami | etcd | 12.0.18 |
| https://nats-io.github.io/k8s/helm/charts/ | nats | 1.3.2 |
| oci://ghcr.io/ai-dynamo/grove | grove(grove-charts) | v0.1.0-alpha.7 |
......
......@@ -27,9 +27,9 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.0.0
version: 1.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.0.0"
appVersion: "1.1.0"
......@@ -16,8 +16,8 @@ apiVersion: v2
name: snapshot
description: Checkpoint/Restore infrastructure for Dynamo (PVC + DaemonSet + CRIU Agent)
type: application
version: 1.0.0
appVersion: "1.0.0"
version: 1.1.0
appVersion: "1.1.0"
keywords:
- nvidia
- dynamo
......
......@@ -1490,14 +1490,14 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "dynamo-config"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
]
[[package]]
name = "dynamo-kv-router"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"async-trait",
......@@ -1524,7 +1524,7 @@ dependencies = [
[[package]]
name = "dynamo-llm"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"aho-corasick",
"aligned-vec",
......@@ -1609,7 +1609,7 @@ dependencies = [
[[package]]
name = "dynamo-memory"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"cudarc",
......@@ -1625,7 +1625,7 @@ dependencies = [
[[package]]
name = "dynamo-mocker"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"dashmap",
......@@ -1652,7 +1652,7 @@ dependencies = [
[[package]]
name = "dynamo-parsers"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"dynamo-protocols",
......@@ -1669,7 +1669,7 @@ dependencies = [
[[package]]
name = "dynamo-protocols"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"async-openai",
"derive_builder",
......@@ -1684,7 +1684,7 @@ dependencies = [
[[package]]
name = "dynamo-runtime"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"arc-swap",
......@@ -1751,7 +1751,7 @@ dependencies = [
[[package]]
name = "dynamo-tokens"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"bs58",
"bytemuck",
......@@ -3229,7 +3229,7 @@ dependencies = [
[[package]]
name = "kvbm-py3"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"cudarc",
......
......@@ -5,7 +5,7 @@
[package]
name = "kvbm-py3"
version = "1.0.0"
version = "1.1.0"
edition = "2024"
authors = ["NVIDIA"]
license = "Apache-2.0"
......
......@@ -16,7 +16,7 @@
[project]
name = "kvbm"
version = "1.0.0"
version = "1.1.0"
description = "Dynamo KVBM"
readme = "README.md"
authors = [
......
......@@ -1498,14 +1498,14 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "dynamo-config"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
]
[[package]]
name = "dynamo-kv-router"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"async-trait",
......@@ -1536,7 +1536,7 @@ dependencies = [
[[package]]
name = "dynamo-llm"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"aho-corasick",
"aligned-vec",
......@@ -1624,7 +1624,7 @@ dependencies = [
[[package]]
name = "dynamo-memory"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"cudarc",
......@@ -1640,7 +1640,7 @@ dependencies = [
[[package]]
name = "dynamo-mocker"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"dashmap",
......@@ -1667,7 +1667,7 @@ dependencies = [
[[package]]
name = "dynamo-parsers"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"dynamo-protocols",
......@@ -1684,7 +1684,7 @@ dependencies = [
[[package]]
name = "dynamo-protocols"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"async-openai",
"derive_builder",
......@@ -1699,7 +1699,7 @@ dependencies = [
[[package]]
name = "dynamo-py3"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"async-trait",
......@@ -1730,7 +1730,7 @@ dependencies = [
[[package]]
name = "dynamo-runtime"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"anyhow",
"arc-swap",
......@@ -1798,7 +1798,7 @@ dependencies = [
[[package]]
name = "dynamo-tokens"
version = "1.0.0"
version = "1.1.0"
dependencies = [
"bs58",
"bytemuck",
......
......@@ -7,7 +7,7 @@
[package]
name = "dynamo-py3"
version = "1.0.0"
version = "1.1.0"
edition = "2024"
authors = ["NVIDIA"]
license = "Apache-2.0"
......
......@@ -16,7 +16,7 @@
[project]
name = "ai-dynamo-runtime"
version = "1.0.0"
version = "1.1.0"
description = "Dynamo Inference Framework Runtime"
readme = "README.md"
authors = [
......
......@@ -3,7 +3,7 @@
[package]
name = "kvbm-common"
version = "1.0.0"
version = "1.1.0"
edition.workspace = true
description.workspace = true
authors.workspace = true
......
......@@ -3,7 +3,7 @@
[package]
name = "kvbm-engine"
version = "1.0.0"
version = "1.1.0"
edition.workspace = true
authors.workspace = true
license.workspace = true
......
......@@ -3,7 +3,7 @@
[package]
name = "kvbm-kernels"
version = "1.0.0"
version = "1.1.0"
edition.workspace = true
authors.workspace = true
license.workspace = true
......
......@@ -3,7 +3,7 @@
[package]
name = "kvbm-logical"
version = "1.0.0"
version = "1.1.0"
edition.workspace = true
authors.workspace = true
license.workspace = true
......
......@@ -3,7 +3,7 @@
[package]
name = "kvbm-physical"
version = "1.0.0"
version = "1.1.0"
edition.workspace = true
authors.workspace = true
license.workspace = true
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment