chore(release): merge v0.9.0-stewardship into v0.8.54
Includes Paulo's command parity and Gherkin E2E harnesses, HUQIANTAO's concurrency/security fixes, LeoAlex0's runtime_prompt slim, reidliu41's hotbar persistence, HarmonyOS scaffolding, Whaleflow foundation crate, and all v0.9.0 stabilization work.
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate that harvested contributor credit is GitHub-mappable.
|
||||
|
||||
The check is intentionally scoped to new commits. Historical commits may carry
|
||||
raw or local emails, but new harvested commits should use GitHub's numeric
|
||||
`id+login@users.noreply.github.com` address so co-author credit lands in the
|
||||
contributor graph.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DEFAULT_AUTHOR_MAP = ROOT / ".github" / "AUTHOR_MAP"
|
||||
|
||||
IDENTITY_RE = re.compile(r"^\s*(?P<name>.+?)\s*<(?P<email>[^<>]+)>\s*$")
|
||||
CANONICAL_NOREPLY_RE = re.compile(
|
||||
r"^[0-9]+\+[^@\s]+@users\.noreply\.github\.com$", re.IGNORECASE
|
||||
)
|
||||
COAUTHOR_RE = re.compile(
|
||||
r"^Co-authored-by:\s*(?P<name>.*?)\s*<(?P<email>[^<>]+)>\s*$",
|
||||
re.IGNORECASE | re.MULTILINE,
|
||||
)
|
||||
HARVEST_RE = re.compile(r"Harvested from PR #[0-9]+ by @([A-Za-z0-9-]+)")
|
||||
|
||||
BOT_EMAILS = {
|
||||
"codex@local",
|
||||
"codex@example.com",
|
||||
"cursoragent@cursor.com",
|
||||
"noreply@anthropic.com",
|
||||
}
|
||||
BOT_NAMES = ("claude", "codex", "cursor")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Identity:
|
||||
name: str
|
||||
email: str
|
||||
|
||||
def trailer(self) -> str:
|
||||
return f"Co-authored-by: {self.name} <{self.email}>"
|
||||
|
||||
def author(self) -> str:
|
||||
return f"{self.name} <{self.email}>"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Commit:
|
||||
sha: str
|
||||
author_name: str
|
||||
author_email: str
|
||||
subject: str
|
||||
body: str
|
||||
|
||||
|
||||
def norm_key(value: str) -> str:
|
||||
return value.strip().lower()
|
||||
|
||||
|
||||
def github_login_from_noreply(email: str) -> str | None:
|
||||
if not CANONICAL_NOREPLY_RE.match(email):
|
||||
return None
|
||||
local = email.split("@", 1)[0]
|
||||
return local.split("+", 1)[1]
|
||||
|
||||
|
||||
def parse_identity(raw: str, context: str) -> Identity:
|
||||
match = IDENTITY_RE.match(raw)
|
||||
if not match:
|
||||
raise ValueError(f"{context}: expected 'Name <id+login@users.noreply.github.com>'")
|
||||
identity = Identity(match.group("name").strip(), match.group("email").strip())
|
||||
if not CANONICAL_NOREPLY_RE.match(identity.email):
|
||||
raise ValueError(
|
||||
f"{context}: right-hand email must be numeric GitHub noreply, got {identity.email}"
|
||||
)
|
||||
return identity
|
||||
|
||||
|
||||
def load_author_map(path: Path) -> dict[str, Identity]:
|
||||
aliases: dict[str, Identity] = {}
|
||||
for lineno, raw_line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
|
||||
line = raw_line.split("#", 1)[0].strip()
|
||||
if not line:
|
||||
continue
|
||||
if "=" not in line:
|
||||
raise ValueError(f"{path}:{lineno}: expected 'alias = Name <email>'")
|
||||
alias, raw_identity = [part.strip() for part in line.split("=", 1)]
|
||||
identity = parse_identity(raw_identity, f"{path}:{lineno}")
|
||||
key = norm_key(alias)
|
||||
if key in aliases and aliases[key] != identity:
|
||||
raise ValueError(f"{path}:{lineno}: duplicate alias {alias!r}")
|
||||
aliases[key] = identity
|
||||
aliases.setdefault(norm_key(identity.email), identity)
|
||||
aliases.setdefault(norm_key(identity.name), identity)
|
||||
if login := github_login_from_noreply(identity.email):
|
||||
aliases.setdefault(norm_key(login), identity)
|
||||
return aliases
|
||||
|
||||
|
||||
def git_log(commit_range: str) -> list[Commit]:
|
||||
try:
|
||||
raw = subprocess.check_output(
|
||||
[
|
||||
"git",
|
||||
"log",
|
||||
"--format=%H%x00%an%x00%ae%x00%s%x00%B%x1e",
|
||||
commit_range,
|
||||
],
|
||||
cwd=ROOT,
|
||||
text=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
raise RuntimeError(f"failed to read git range {commit_range!r}: {exc}") from exc
|
||||
|
||||
commits: list[Commit] = []
|
||||
for record in raw.split("\x1e"):
|
||||
if not record.strip():
|
||||
continue
|
||||
parts = record.split("\x00", 4)
|
||||
if len(parts) != 5:
|
||||
raise RuntimeError("failed to parse git log output")
|
||||
commits.append(Commit(*parts))
|
||||
return commits
|
||||
|
||||
|
||||
def is_bot_identity(name: str, email: str) -> bool:
|
||||
lowered_name = name.strip().lower()
|
||||
lowered_email = email.strip().lower()
|
||||
return lowered_email in BOT_EMAILS or any(
|
||||
lowered_name == bot or lowered_name.startswith(f"{bot} ") for bot in BOT_NAMES
|
||||
)
|
||||
|
||||
|
||||
def lookup_identity(aliases: dict[str, Identity], *values: str) -> Identity | None:
|
||||
for value in values:
|
||||
identity = aliases.get(norm_key(value))
|
||||
if identity is not None:
|
||||
return identity
|
||||
return None
|
||||
|
||||
|
||||
def validate(commits: list[Commit], aliases: dict[str, Identity], check_authors: bool) -> list[str]:
|
||||
errors: list[str] = []
|
||||
for commit in commits:
|
||||
prefix = f"{commit.sha[:10]} {commit.subject}"
|
||||
coauthors = [
|
||||
Identity(match.group("name").strip(), match.group("email").strip())
|
||||
for match in COAUTHOR_RE.finditer(commit.body)
|
||||
]
|
||||
harvested_logins = HARVEST_RE.findall(commit.body)
|
||||
is_harvested_commit = bool(harvested_logins)
|
||||
mapped_author = lookup_identity(aliases, commit.author_email, commit.author_name)
|
||||
|
||||
if check_authors:
|
||||
if is_harvested_commit and is_bot_identity(commit.author_name, commit.author_email):
|
||||
errors.append(
|
||||
f"{prefix}: author {commit.author_name} <{commit.author_email}> is a "
|
||||
"bot/tool identity. Human harvested work should preserve the contributor "
|
||||
"as author or use a human co-author trailer."
|
||||
)
|
||||
elif (
|
||||
is_harvested_commit
|
||||
and mapped_author
|
||||
and norm_key(commit.author_email) != norm_key(mapped_author.email)
|
||||
):
|
||||
errors.append(
|
||||
f"{prefix}: author {commit.author_name} <{commit.author_email}> "
|
||||
f"matches AUTHOR_MAP but is not canonical. Use author {mapped_author.author()}."
|
||||
)
|
||||
|
||||
for coauthor in coauthors:
|
||||
if CANONICAL_NOREPLY_RE.match(coauthor.email):
|
||||
continue
|
||||
if is_bot_identity(coauthor.name, coauthor.email):
|
||||
if is_harvested_commit:
|
||||
errors.append(
|
||||
f"{prefix}: remove bot/tool co-author trailer "
|
||||
f"{coauthor.name} <{coauthor.email}>; contributor trailers are for humans."
|
||||
)
|
||||
continue
|
||||
expected = lookup_identity(aliases, coauthor.email, coauthor.name)
|
||||
if expected:
|
||||
errors.append(
|
||||
f"{prefix}: co-author {coauthor.name} <{coauthor.email}> is not "
|
||||
f"GitHub-mappable. Use `{expected.trailer()}`."
|
||||
)
|
||||
else:
|
||||
errors.append(
|
||||
f"{prefix}: co-author {coauthor.name} <{coauthor.email}> is not "
|
||||
"numeric GitHub noreply and has no AUTHOR_MAP entry. Add an alias "
|
||||
"or use `gh api users/<login> --jq '\"\\(.id)+\\(.login)@users.noreply.github.com\"'`."
|
||||
)
|
||||
|
||||
coauthor_emails = {norm_key(coauthor.email) for coauthor in coauthors}
|
||||
for login in harvested_logins:
|
||||
expected = lookup_identity(aliases, login)
|
||||
if expected is None:
|
||||
errors.append(
|
||||
f"{prefix}: harvested contributor @{login} is missing from .github/AUTHOR_MAP."
|
||||
)
|
||||
continue
|
||||
if (
|
||||
norm_key(commit.author_email) != norm_key(expected.email)
|
||||
and norm_key(expected.email) not in coauthor_emails
|
||||
):
|
||||
errors.append(
|
||||
f"{prefix}: `Harvested from PR ... by @{login}` needs machine-readable "
|
||||
f"credit. Add `{expected.trailer()}` or preserve the contributor as author."
|
||||
)
|
||||
return errors
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--author-map", type=Path, default=DEFAULT_AUTHOR_MAP)
|
||||
parser.add_argument("--range", default="origin/main..HEAD", help="git commit range to check")
|
||||
parser.add_argument(
|
||||
"--check-authors",
|
||||
action="store_true",
|
||||
help="also reject commit author emails that match known AUTHOR_MAP aliases",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
try:
|
||||
aliases = load_author_map(args.author_map)
|
||||
commits = git_log(args.range)
|
||||
errors = validate(commits, aliases, args.check_authors)
|
||||
except Exception as exc:
|
||||
print(f"co-author credit check failed to run: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
if errors:
|
||||
print("Co-author credit check failed:", file=sys.stderr)
|
||||
for error in errors:
|
||||
print(f"- {error}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print(f"Co-author credit check passed for {len(commits)} commit(s).")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
@@ -0,0 +1,57 @@
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Stop-OhosEnv {
|
||||
param([string]$Message)
|
||||
|
||||
[Console]::Error.WriteLine("error: $Message")
|
||||
throw "OpenHarmony Cargo environment setup failed."
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($env:OHOS_NATIVE_SDK)) {
|
||||
Stop-OhosEnv "set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory."
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $env:OHOS_NATIVE_SDK -PathType Container -ErrorAction SilentlyContinue)) {
|
||||
Stop-OhosEnv "OHOS_NATIVE_SDK does not exist: $env:OHOS_NATIVE_SDK"
|
||||
}
|
||||
|
||||
$sdk = (Resolve-Path -LiteralPath $env:OHOS_NATIVE_SDK -ErrorAction Stop).Path
|
||||
$clang = [System.IO.Path]::Combine($sdk, "llvm", "bin", "clang.exe")
|
||||
$clangxx = [System.IO.Path]::Combine($sdk, "llvm", "bin", "clang++.exe")
|
||||
$ar = [System.IO.Path]::Combine($sdk, "llvm", "bin", "llvm-ar.exe")
|
||||
$sysroot = [System.IO.Path]::Combine($sdk, "sysroot")
|
||||
$cmakeToolchain = [System.IO.Path]::Combine($sdk, "build", "cmake", "ohos.toolchain.cmake")
|
||||
|
||||
$requiredFiles = @($clang, $clangxx, $ar, $cmakeToolchain)
|
||||
foreach ($path in $requiredFiles) {
|
||||
if (-not (Test-Path -LiteralPath $path -PathType Leaf -ErrorAction SilentlyContinue)) {
|
||||
Stop-OhosEnv "required OpenHarmony SDK file is missing: $path"
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $sysroot -PathType Container -ErrorAction SilentlyContinue)) {
|
||||
Stop-OhosEnv "required OpenHarmony SDK sysroot is missing: $sysroot"
|
||||
}
|
||||
|
||||
$target = "aarch64_unknown_linux_ohos"
|
||||
$targetUpper = "AARCH64_UNKNOWN_LINUX_OHOS"
|
||||
$commonFlags = "-target aarch64-linux-ohos --sysroot=`"$sysroot`" -D__MUSL__"
|
||||
|
||||
$env:CARGO_TARGET_AARCH64_UNKNOWN_LINUX_OHOS_LINKER = $clang
|
||||
$env:AR_aarch64_unknown_linux_ohos = $ar
|
||||
$env:CC_aarch64_unknown_linux_ohos = $clang
|
||||
$env:CXX_aarch64_unknown_linux_ohos = $clangxx
|
||||
$env:CC_SHELL_ESCAPED_FLAGS = "1"
|
||||
Set-Item -Path "Env:CFLAGS_$target" -Value $commonFlags
|
||||
Set-Item -Path "Env:CXXFLAGS_$target" -Value $commonFlags
|
||||
Set-Item -Path "Env:CMAKE_TOOLCHAIN_FILE_$target" -Value $cmakeToolchain
|
||||
|
||||
$separator = [char]0x1f
|
||||
$env:CARGO_ENCODED_RUSTFLAGS = @(
|
||||
"-Clink-arg=-target",
|
||||
"-Clink-arg=aarch64-linux-ohos",
|
||||
"-Clink-arg=--sysroot=$sysroot",
|
||||
"-Clink-arg=-D__MUSL__"
|
||||
) -join $separator
|
||||
|
||||
Write-Host "Configured OpenHarmony Cargo environment for $targetUpper from $sdk"
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
if [ -z "${OHOS_NATIVE_SDK:-}" ]; then
|
||||
echo "error: set OHOS_NATIVE_SDK to the OpenHarmony native SDK directory." >&2
|
||||
return 1 2>/dev/null || exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$OHOS_NATIVE_SDK" ]; then
|
||||
echo "error: OHOS_NATIVE_SDK does not exist: $OHOS_NATIVE_SDK" >&2
|
||||
return 1 2>/dev/null || exit 1
|
||||
fi
|
||||
|
||||
sdk=$(cd "$OHOS_NATIVE_SDK" && pwd)
|
||||
clang=$sdk/llvm/bin/clang
|
||||
clangxx=$sdk/llvm/bin/clang++
|
||||
ar=$sdk/llvm/bin/llvm-ar
|
||||
sysroot=$sdk/sysroot
|
||||
cmake_toolchain=$sdk/build/cmake/ohos.toolchain.cmake
|
||||
|
||||
for file in "$clang" "$clangxx" "$ar" "$cmake_toolchain"; do
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "error: required OpenHarmony SDK file is missing: $file" >&2
|
||||
return 1 2>/dev/null || exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -d "$sysroot" ]; then
|
||||
echo "error: required OpenHarmony SDK sysroot is missing: $sysroot" >&2
|
||||
return 1 2>/dev/null || exit 1
|
||||
fi
|
||||
|
||||
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_OHOS_LINKER=$clang
|
||||
export AR_aarch64_unknown_linux_ohos=$ar
|
||||
export CC_aarch64_unknown_linux_ohos=$clang
|
||||
export CXX_aarch64_unknown_linux_ohos=$clangxx
|
||||
export CC_SHELL_ESCAPED_FLAGS=1
|
||||
export CFLAGS_aarch64_unknown_linux_ohos="-target aarch64-linux-ohos --sysroot=\"$sysroot\" -D__MUSL__"
|
||||
export CXXFLAGS_aarch64_unknown_linux_ohos="-target aarch64-linux-ohos --sysroot=\"$sysroot\" -D__MUSL__"
|
||||
export CMAKE_TOOLCHAIN_FILE_aarch64_unknown_linux_ohos=$cmake_toolchain
|
||||
|
||||
sep=$(printf '\037')
|
||||
export CARGO_ENCODED_RUSTFLAGS="-Clink-arg=-target${sep}-Clink-arg=aarch64-linux-ohos${sep}-Clink-arg=--sysroot=$sysroot${sep}-Clink-arg=-D__MUSL__"
|
||||
|
||||
echo "Configured OpenHarmony Cargo environment for AARCH64_UNKNOWN_LINUX_OHOS from $sdk"
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
# Guard the OpenHarmony target dependency graph.
|
||||
#
|
||||
# This check intentionally does not require an OpenHarmony SDK or sysroot. It
|
||||
# only asks Cargo to resolve the codewhale-tui dependency graph for the OHOS
|
||||
# target and fails if crates known to break or be unsupported on OHOS re-enter
|
||||
# that graph.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
target="${1:-aarch64-unknown-linux-ohos}"
|
||||
package="${CODEWHALE_OHOS_DEP_PACKAGE:-codewhale-tui}"
|
||||
|
||||
tree="$(
|
||||
cargo tree \
|
||||
--locked \
|
||||
--package "${package}" \
|
||||
--all-features \
|
||||
--target "${target}" \
|
||||
--prefix none \
|
||||
--no-dedupe
|
||||
)"
|
||||
|
||||
disallowed="$(
|
||||
grep -E '^(nix v0\.(28|29)\.|portable-pty v|starlark v|arboard v|keyring v)' <<<"${tree}" || true
|
||||
)"
|
||||
|
||||
if [[ -n "${disallowed}" ]]; then
|
||||
{
|
||||
echo "::error::OHOS target graph for ${package} includes unsupported dependencies:"
|
||||
echo "${disallowed}"
|
||||
echo
|
||||
echo "The OpenHarmony port avoids the rustyline/starlark/portable-pty/nix chain"
|
||||
echo "by target-gating those crates away from target_env=ohos. Keep this graph"
|
||||
echo "clean unless a real OHOS-compatible dependency update lands."
|
||||
} >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "OHOS dependency graph OK for ${package} on ${target}."
|
||||
@@ -96,10 +96,22 @@ if [[ -z "${compare_line}" ]]; then
|
||||
fail=1
|
||||
fi
|
||||
|
||||
unreleased_section="$(
|
||||
awk '
|
||||
index($0, "## [Unreleased]") == 1 { in_section = 1; print; next }
|
||||
in_section && /^## \[/ { exit }
|
||||
in_section { print }
|
||||
' CHANGELOG.md
|
||||
)"
|
||||
credit_sections="${current_section}
|
||||
${unreleased_section}"
|
||||
|
||||
# 6) Contributor-credit cross-check for README additions on the release branch.
|
||||
# This cannot prove every external PR author has been credited, but it does
|
||||
# catch the common release-polish failure mode: adding a README contributor row
|
||||
# without mentioning that credit/correction in the current release entry.
|
||||
# without mentioning that credit/correction in the current release entry. While
|
||||
# a release branch is still unbumped, `[Unreleased]` is also a valid credit
|
||||
# surface.
|
||||
previous_tag=""
|
||||
current_tag="v${workspace_version}"
|
||||
if [[ "${compare_line}" =~ compare/(v[0-9]+\.[0-9]+\.[0-9]+)\.\.\.${current_tag} ]]; then
|
||||
@@ -114,8 +126,8 @@ if [[ -n "${previous_tag}" ]]; then
|
||||
[[ -z "${line}" ]] && continue
|
||||
handle="$(sed -E 's#.*github.com/([^)/]+).*#\1#' <<<"${line}")"
|
||||
if [[ -n "${handle}" && "${handle}" != "${line}" ]]; then
|
||||
if ! grep -Fq "github.com/${handle}" <<<"${current_section}" && ! grep -Fq "@${handle}" <<<"${current_section}"; then
|
||||
echo "::error::README.md adds contributor @${handle}, but CHANGELOG.md ${workspace_version} does not mention that credit." >&2
|
||||
if ! grep -Fq "github.com/${handle}" <<<"${credit_sections}" && ! grep -Fq "@${handle}" <<<"${credit_sections}"; then
|
||||
echo "::error::README.md adds contributor @${handle}, but CHANGELOG.md ${workspace_version} or [Unreleased] does not mention that credit." >&2
|
||||
fail=1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -2,19 +2,20 @@
|
||||
|
||||
# Crates published for each codewhale release, in dependency order.
|
||||
release_crates=(
|
||||
codewhale-secrets
|
||||
codewhale-release
|
||||
codewhale-config
|
||||
codewhale-mcp
|
||||
codewhale-protocol
|
||||
codewhale-release
|
||||
codewhale-secrets
|
||||
codewhale-state
|
||||
codewhale-agent
|
||||
codewhale-tui-core
|
||||
codewhale-whaleflow
|
||||
codewhale-execpolicy
|
||||
codewhale-hooks
|
||||
codewhale-mcp
|
||||
codewhale-tools
|
||||
codewhale-config
|
||||
codewhale-agent
|
||||
codewhale-tui
|
||||
codewhale-core
|
||||
codewhale-app-server
|
||||
codewhale-tui-core
|
||||
codewhale-cli
|
||||
codewhale-tui
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@ case "${mode}" in
|
||||
esac
|
||||
|
||||
packages=("${release_crates[@]}")
|
||||
crates_user_agent="CodeWhale release publish check (https://github.com/Hmbown/CodeWhale)"
|
||||
|
||||
workspace_version=""
|
||||
workspace_codewhale_packages=()
|
||||
@@ -122,7 +123,7 @@ package_has_workspace_deps() {
|
||||
crate_version_exists() {
|
||||
local crate_name="$1"
|
||||
local crate_version="$2"
|
||||
curl -fsSL "https://crates.io/api/v1/crates/${crate_name}/${crate_version}" >/dev/null 2>&1
|
||||
curl -fsSL -A "${crates_user_agent}" "https://crates.io/api/v1/crates/${crate_name}/${crate_version}" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
wait_for_crate_version() {
|
||||
|
||||
+24
-6
@@ -2,13 +2,31 @@
|
||||
# verify_task.sh <task_id> <docker_image>
|
||||
# Runs the DeepSWE verifier inside the task's Docker container.
|
||||
# Expects model.patch at /tmp/deep-swe-verify/<task_id>/model.patch
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: $0 <task_id> <docker_image>" >&2
|
||||
exit 64
|
||||
fi
|
||||
|
||||
TASK_ID="$1"
|
||||
IMAGE="$2"
|
||||
TASKS_DIR="/Volumes/VIXinSSD/whalebro/codewhale/deep-swe/tasks"
|
||||
WORK_DIR="/tmp/deep-swe-verify/$TASK_ID"
|
||||
TASKS_DIR="${DEEPSWE_TASKS_DIR:-/Volumes/VIXinSSD/whalebro/codewhale/deep-swe/tasks}"
|
||||
WORK_BASE="${DEEPSWE_VERIFY_DIR:-/tmp/deep-swe-verify}"
|
||||
WORK_DIR="$WORK_BASE/$TASK_ID"
|
||||
|
||||
mkdir -p "$WORK_DIR"
|
||||
RESULT_FILE="$WORK_DIR/result.txt"
|
||||
MODEL_PATCH="$WORK_DIR/model.patch"
|
||||
TEST_PATCH="$TASKS_DIR/$TASK_ID/tests/test.patch"
|
||||
TEST_SCRIPT="$TASKS_DIR/$TASK_ID/tests/test.sh"
|
||||
|
||||
for required in "$MODEL_PATCH" "$TEST_PATCH" "$TEST_SCRIPT"; do
|
||||
if [[ ! -f "$required" ]]; then
|
||||
echo "missing required file: $required" >&2
|
||||
exit 66
|
||||
fi
|
||||
done
|
||||
|
||||
echo "[$TASK_ID] Pulling image..."
|
||||
docker pull "$IMAGE" 2>&1 | tail -1
|
||||
@@ -16,9 +34,9 @@ docker pull "$IMAGE" 2>&1 | tail -1
|
||||
echo "[$TASK_ID] Running verifier..."
|
||||
docker run --rm \
|
||||
--platform linux/amd64 \
|
||||
-v "$WORK_DIR/model.patch:/model.patch:ro" \
|
||||
-v "$TASKS_DIR/$TASK_ID/tests/test.patch:/tests/test.patch:ro" \
|
||||
-v "$TASKS_DIR/$TASK_ID/tests/test.sh:/verify.sh:ro" \
|
||||
-v "$MODEL_PATCH:/model.patch:ro" \
|
||||
-v "$TEST_PATCH:/tests/test.patch:ro" \
|
||||
-v "$TEST_SCRIPT:/verify.sh:ro" \
|
||||
"$IMAGE" \
|
||||
bash -c '
|
||||
set -e
|
||||
@@ -44,5 +62,5 @@ docker run --rm \
|
||||
' > "$RESULT_FILE" 2>&1
|
||||
|
||||
echo "[$TASK_ID] Done. Result:"
|
||||
cat "$RESULT_FILE" | grep -E 'REWARD|FAILED|PATCH_FAILED|passed'
|
||||
grep -E 'REWARD|FAILED|PATCH_FAILED|passed' "$RESULT_FILE" || true
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user