release prep: rc.1 baseline and gating updates

This commit is contained in:
2026-03-02 15:54:55 -05:00
parent 97a42c8802
commit f43b2b24b6
168 changed files with 14708 additions and 982 deletions

View File

@@ -5,9 +5,9 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
forbidden_pattern='decompiled(_dll|_autoupdate)?/|bundle_extract/|extracted(_net)?/|session-ses_35e4|8BitDo_Ultimate_Software_V2\.decompiled\.cs'
scan_paths=(crates tests .github)
scan_paths=(crates tests scripts ../.github)
if rg -n --hidden -g '!target/**' "$forbidden_pattern" "${scan_paths[@]}"; then
if rg -n --hidden -g '!target/**' -g '!scripts/cleanroom_guard.sh' "$forbidden_pattern" "${scan_paths[@]}"; then
echo "cleanroom guard failed: forbidden dirty-room reference detected"
exit 1
fi

68
sdk/scripts/package-linux.sh Executable file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO_ROOT="$(cd "$ROOT/.." && pwd)"
VERSION="${1:-v0.0.1-rc.1}"
ARCH_LABEL="${2:-$(uname -m)}"
TARGET_TRIPLE="${3:-}"
if [[ "$(uname -s)" != "Linux" ]]; then
echo "package-linux.sh must run on Linux" >&2
exit 1
fi
case "$ARCH_LABEL" in
x86_64|aarch64) ;;
arm64) ARCH_LABEL="aarch64" ;;
*)
echo "unsupported linux arch label: $ARCH_LABEL" >&2
exit 1
;;
esac
DIST_ROOT="$ROOT/dist"
PKG_NAME="openbitdo-${VERSION}-linux-${ARCH_LABEL}"
PKG_DIR="$DIST_ROOT/$PKG_NAME"
BIN_ASSET="$DIST_ROOT/${PKG_NAME}"
checksum_file() {
local path="$1"
if command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$path" > "${path}.sha256"
elif command -v sha256sum >/dev/null 2>&1; then
sha256sum "$path" > "${path}.sha256"
else
echo "warning: no checksum tool found for $path" >&2
fi
}
build_binary() {
cd "$ROOT"
if [[ -n "$TARGET_TRIPLE" ]]; then
cargo build --release -p openbitdo --target "$TARGET_TRIPLE"
echo "$ROOT/target/$TARGET_TRIPLE/release/openbitdo"
else
cargo build --release -p openbitdo
echo "$ROOT/target/release/openbitdo"
fi
}
BIN_PATH="$(build_binary)"
rm -rf "$PKG_DIR"
mkdir -p "$PKG_DIR/bin" "$DIST_ROOT"
cp "$BIN_PATH" "$PKG_DIR/bin/openbitdo"
cp "$BIN_PATH" "$BIN_ASSET"
cp "$REPO_ROOT/README.md" "$PKG_DIR/README.md"
cp "$ROOT/README.md" "$PKG_DIR/SDK_README.md"
cp "$REPO_ROOT/LICENSE" "$PKG_DIR/LICENSE"
tar -C "$DIST_ROOT" -czf "$DIST_ROOT/${PKG_NAME}.tar.gz" "$PKG_NAME"
checksum_file "$DIST_ROOT/${PKG_NAME}.tar.gz"
checksum_file "$BIN_ASSET"
echo "created package: $DIST_ROOT/${PKG_NAME}.tar.gz"
echo "created standalone binary: $BIN_ASSET"

77
sdk/scripts/package-macos.sh Executable file
View File

@@ -0,0 +1,77 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO_ROOT="$(cd "$ROOT/.." && pwd)"
VERSION="${1:-v0.0.1-rc.1}"
ARCH_LABEL="${2:-arm64}"
TARGET_TRIPLE="${3:-aarch64-apple-darwin}"
INSTALL_PREFIX="${4:-/opt/homebrew/bin}"
if [[ "$(uname -s)" != "Darwin" ]]; then
echo "package-macos.sh must run on macOS" >&2
exit 1
fi
if [[ "$ARCH_LABEL" != "arm64" ]]; then
echo "unsupported macOS arch label: $ARCH_LABEL (expected arm64)" >&2
exit 1
fi
DIST_ROOT="$ROOT/dist"
PKG_NAME="openbitdo-${VERSION}-macos-${ARCH_LABEL}"
PKG_DIR="$DIST_ROOT/$PKG_NAME"
BIN_ASSET="$DIST_ROOT/${PKG_NAME}"
PKG_ASSET="$DIST_ROOT/${PKG_NAME}.pkg"
PKGROOT="$DIST_ROOT/${PKG_NAME}-pkgroot"
checksum_file() {
local path="$1"
if command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$path" > "${path}.sha256"
elif command -v sha256sum >/dev/null 2>&1; then
sha256sum "$path" > "${path}.sha256"
else
echo "warning: no checksum tool found for $path" >&2
fi
}
build_binary() {
cd "$ROOT"
cargo build --release -p openbitdo --target "$TARGET_TRIPLE"
echo "$ROOT/target/$TARGET_TRIPLE/release/openbitdo"
}
BIN_PATH="$(build_binary)"
VERSION_STRIPPED="${VERSION#v}"
rm -rf "$PKG_DIR" "$PKGROOT" "$PKG_ASSET"
mkdir -p "$PKG_DIR/bin" "$DIST_ROOT"
cp "$BIN_PATH" "$PKG_DIR/bin/openbitdo"
cp "$BIN_PATH" "$BIN_ASSET"
cp "$REPO_ROOT/README.md" "$PKG_DIR/README.md"
cp "$ROOT/README.md" "$PKG_DIR/SDK_README.md"
cp "$REPO_ROOT/LICENSE" "$PKG_DIR/LICENSE"
tar -C "$DIST_ROOT" -czf "$DIST_ROOT/${PKG_NAME}.tar.gz" "$PKG_NAME"
mkdir -p "$PKGROOT${INSTALL_PREFIX}"
cp "$BIN_PATH" "$PKGROOT${INSTALL_PREFIX}/openbitdo"
chmod 755 "$PKGROOT${INSTALL_PREFIX}/openbitdo"
pkgbuild \
--root "$PKGROOT" \
--identifier "io.openbitdo.cli" \
--version "$VERSION_STRIPPED" \
"$PKG_ASSET"
rm -rf "$PKGROOT"
checksum_file "$DIST_ROOT/${PKG_NAME}.tar.gz"
checksum_file "$BIN_ASSET"
checksum_file "$PKG_ASSET"
echo "created package: $DIST_ROOT/${PKG_NAME}.tar.gz"
echo "created standalone binary: $BIN_ASSET"
echo "created installer pkg: $PKG_ASSET"

View File

@@ -3,37 +3,234 @@ set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
LAB_CONFIG="${ROOT}/../harness/lab/device_lab.yaml"
if [[ ! -f "$LAB_CONFIG" ]]; then
echo "missing lab config: $LAB_CONFIG" >&2
exit 1
fi
REPORT_DIR="${ROOT}/../harness/reports"
mkdir -p "$REPORT_DIR"
TS="$(date +%Y%m%d-%H%M%S)"
REPORT_PATH="${1:-$REPORT_DIR/hardware_smoke_${TS}.json}"
LIST_JSON="$(cargo run -q -p bitdoctl -- --json list 2>/dev/null || echo '[]')"
SUITE="${BITDO_REQUIRED_SUITE:-family}"
REQUIRED_FAMILIES="${BITDO_REQUIRED_FAMILIES:-Standard64,DInput}"
TEST_OUTPUT_FILE="$(mktemp)"
PARSE_OUTPUT="$(mktemp)"
set +e
BITDO_HARDWARE=1 cargo test --workspace --test hardware_smoke -- --ignored >"$TEST_OUTPUT_FILE" 2>&1
TEST_STATUS=$?
python3 - <<'PY' "$LAB_CONFIG" "$SUITE" "$REQUIRED_FAMILIES" >"$PARSE_OUTPUT"
import pathlib
import re
import sys
config_path = pathlib.Path(sys.argv[1])
suite = sys.argv[2].strip()
required_families = [item.strip() for item in sys.argv[3].split(",") if item.strip()]
lines = config_path.read_text().splitlines()
devices = []
current = None
in_devices = False
def parse_scalar(text: str):
value = text.split("#", 1)[0].strip()
if not value:
return value
if value.startswith(("0x", "0X")):
return int(value, 16)
try:
return int(value)
except ValueError:
return value
for line in lines:
stripped = line.strip()
if stripped.startswith("devices:"):
in_devices = True
continue
if not in_devices:
continue
if stripped.startswith("policies:"):
if current:
devices.append(current)
current = None
break
if re.match(r"^\s*-\s+", line):
if current:
devices.append(current)
current = {}
continue
if current is None:
continue
field_match = re.match(r"^\s*([A-Za-z0-9_]+)\s*:\s*(.+)$", line)
if not field_match:
continue
key = field_match.group(1)
value = parse_scalar(field_match.group(2))
current[key] = value
if current:
devices.append(current)
if not devices:
sys.stderr.write(f"no devices found in {config_path}\n")
sys.exit(1)
family_to_pid = {}
fixture_to_pid = {}
for device in devices:
family = device.get("protocol_family")
pid = device.get("pid")
fixture_id = device.get("fixture_id")
if isinstance(family, str) and isinstance(pid, int) and family not in family_to_pid:
family_to_pid[family] = pid
if isinstance(fixture_id, str) and isinstance(pid, int) and fixture_id not in fixture_to_pid:
fixture_to_pid[fixture_id] = pid
if suite == "family":
missing = [fam for fam in required_families if fam not in family_to_pid]
if missing:
available = ", ".join(sorted(family_to_pid.keys())) if family_to_pid else "none"
sys.stderr.write(
f"missing required family fixtures in {config_path}: {', '.join(missing)}; available: {available}\n"
)
sys.exit(1)
for fam in required_families:
print(f"FAMILY:{fam}={family_to_pid[fam]:#06x}")
elif suite == "ultimate2":
if "ultimate2" not in fixture_to_pid:
available = ", ".join(sorted(fixture_to_pid.keys())) if fixture_to_pid else "none"
sys.stderr.write(
f"missing fixture_id=ultimate2 in {config_path}; available fixture_ids: {available}\n"
)
sys.exit(1)
print(f"FIXTURE:ultimate2={fixture_to_pid['ultimate2']:#06x}")
elif suite == "108jp":
if "108jp" not in fixture_to_pid:
available = ", ".join(sorted(fixture_to_pid.keys())) if fixture_to_pid else "none"
sys.stderr.write(
f"missing fixture_id=108jp in {config_path}; available fixture_ids: {available}\n"
)
sys.exit(1)
print(f"FIXTURE:108jp={fixture_to_pid['108jp']:#06x}")
else:
sys.stderr.write(f"unsupported BITDO_REQUIRED_SUITE value: {suite}\n")
sys.exit(1)
PY
PARSE_STATUS=$?
set -e
python3 - <<'PY' "$REPORT_PATH" "$TEST_STATUS" "$TEST_OUTPUT_FILE" "$LIST_JSON"
if [[ $PARSE_STATUS -ne 0 ]]; then
rm -f "$PARSE_OUTPUT"
exit $PARSE_STATUS
fi
while IFS='=' read -r key pid_hex; do
[[ -z "$key" ]] && continue
if [[ "$key" == FAMILY:* ]]; then
family="${key#FAMILY:}"
case "$family" in
DInput) export BITDO_EXPECT_DINPUT_PID="$pid_hex" ;;
Standard64) export BITDO_EXPECT_STANDARD64_PID="$pid_hex" ;;
JpHandshake) export BITDO_EXPECT_JPHANDSHAKE_PID="$pid_hex" ;;
*)
echo "unsupported family in parsed lab config: $family" >&2
rm -f "$PARSE_OUTPUT"
exit 1
;;
esac
elif [[ "$key" == FIXTURE:* ]]; then
fixture="${key#FIXTURE:}"
case "$fixture" in
ultimate2) export BITDO_EXPECT_ULTIMATE2_PID="$pid_hex" ;;
108jp) export BITDO_EXPECT_108JP_PID="$pid_hex" ;;
*)
echo "unsupported fixture in parsed lab config: $fixture" >&2
rm -f "$PARSE_OUTPUT"
exit 1
;;
esac
fi
done <"$PARSE_OUTPUT"
rm -f "$PARSE_OUTPUT"
TEST_OUTPUT_FILE="$(mktemp)"
TEST_STATUS=0
run_test() {
local test_name="$1"
set +e
BITDO_HARDWARE=1 cargo test --workspace --test hardware_smoke -- --ignored --exact "$test_name" >>"$TEST_OUTPUT_FILE" 2>&1
local status=$?
set -e
if [[ $status -ne 0 ]]; then
TEST_STATUS=$status
fi
}
run_test "hardware_smoke_detect_devices"
case "$SUITE" in
family)
IFS=',' read -r -a FAMILY_LIST <<<"$REQUIRED_FAMILIES"
for family in "${FAMILY_LIST[@]}"; do
case "$family" in
DInput) run_test "hardware_smoke_dinput_family" ;;
Standard64) run_test "hardware_smoke_standard64_family" ;;
JpHandshake) run_test "hardware_smoke_jphandshake_family" ;;
*)
echo "unsupported required family for tests: $family" >>"$TEST_OUTPUT_FILE"
TEST_STATUS=1
;;
esac
done
;;
ultimate2)
run_test "hardware_smoke_ultimate2_core_ops"
;;
108jp)
run_test "hardware_smoke_108jp_dedicated_ops"
;;
*)
echo "unsupported suite: $SUITE" >>"$TEST_OUTPUT_FILE"
TEST_STATUS=1
;;
esac
python3 - <<'PY' "$REPORT_PATH" "$TEST_STATUS" "$TEST_OUTPUT_FILE" "$SUITE" "$REQUIRED_FAMILIES" "${BITDO_EXPECT_STANDARD64_PID:-}" "${BITDO_EXPECT_DINPUT_PID:-}" "${BITDO_EXPECT_JPHANDSHAKE_PID:-}" "${BITDO_EXPECT_ULTIMATE2_PID:-}" "${BITDO_EXPECT_108JP_PID:-}"
import json, sys, pathlib, datetime
report_path = pathlib.Path(sys.argv[1])
test_status = int(sys.argv[2])
output_file = pathlib.Path(sys.argv[3])
list_json_raw = sys.argv[4]
try:
devices = json.loads(list_json_raw)
except Exception:
devices = []
suite = sys.argv[4]
required_families = [x for x in sys.argv[5].split(",") if x]
expected_standard64 = sys.argv[6]
expected_dinput = sys.argv[7]
expected_jphandshake = sys.argv[8]
expected_ultimate2 = sys.argv[9]
expected_108jp = sys.argv[10]
report = {
"timestamp_utc": datetime.datetime.utcnow().isoformat() + "Z",
"suite": suite,
"test_status": test_status,
"tests_passed": test_status == 0,
"devices": devices,
"required_families": required_families,
"required_family_fixtures": {
"Standard64": expected_standard64,
"DInput": expected_dinput,
"JpHandshake": expected_jphandshake,
},
"required_device_fixtures": {
"ultimate2": expected_ultimate2,
"108jp": expected_108jp,
},
"raw_test_output": output_file.read_text(errors="replace"),
}
@@ -43,3 +240,4 @@ PY
rm -f "$TEST_OUTPUT_FILE"
echo "hardware smoke report written: $REPORT_PATH"
exit "$TEST_STATUS"