From 6911ef015c43814d79ce505e39597fec2e82728a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 20 Sep 2026 14:42:53 +0000 Subject: [PATCH 1/2] =?UTF-8?q?feat(v1.16.0):=20=E6=8C=89=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E9=A1=BA=E5=BA=8F=E5=B0=86=20workspace=20crate=20?= =?UTF-8?q?=E5=8F=91=E5=B8=83=E5=88=B0=20crates.io?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为 amber_transpile / amber_sandbox 补齐 path+version 与 crates.io 元数据, 收紧并修正 amberjs 的 include 白名单,并在 Release Assets 中按依赖顺序 幂等发布(已存在版本跳过)。 Co-authored-by: Henry Zhang --- .github/workflows/release-assets.yml | 47 ++++- Cargo.toml | 52 ++---- README.md | 7 + apps/website/src/docs/installation.md | 8 + apps/website/src/docs/installation.zh.md | 8 + crates/amber_sandbox/Cargo.toml | 7 + crates/amber_sandbox/README.md | 9 + crates/amber_transpile/Cargo.toml | 7 + crates/amber_transpile/README.md | 9 + docs/CONTRIBUTING.md | 2 + docs/GITHUB_ACTIONS_RUNTIME_INFRASTRUCTURE.md | 4 +- tests/release_workflow_tests.rs | 164 ++++++++++++++++++ 12 files changed, 278 insertions(+), 46 deletions(-) create mode 100644 crates/amber_sandbox/README.md create mode 100644 crates/amber_transpile/README.md diff --git a/.github/workflows/release-assets.yml b/.github/workflows/release-assets.yml index 51fb5423..1a9e93ce 100644 --- a/.github/workflows/release-assets.yml +++ b/.github/workflows/release-assets.yml @@ -144,7 +144,7 @@ jobs: name: GitHub Release if: ${{ always() && !cancelled() && (startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') }} runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 60 needs: build-assets env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} @@ -267,6 +267,49 @@ jobs: if: env.CARGO_REGISTRY_TOKEN != '' uses: dtolnay/rust-toolchain@1.97.1 + - name: Cache cargo registry + if: env.CARGO_REGISTRY_TOKEN != '' + uses: Swatinem/rust-cache@v2 + with: + shared-key: crates-io-publish + cache-targets: false + cache-on-failure: true + + # Members first (path+version deps), then root. Re-runs on workflow_dispatch + # treat "already uploaded" as success. A publish failure after GitHub + # Release is intentional so the missing crates.io crate is visible. - name: Publish to crates.io if: env.CARGO_REGISTRY_TOKEN != '' - run: cargo publish --locked --token "$CARGO_REGISTRY_TOKEN" + run: | + set -euo pipefail + publish_one() { + local pkg="$1" + local attempt + for attempt in 1 2 3 4 5; do + local log + log="$(mktemp)" + set +e + cargo publish -p "$pkg" --locked --token "$CARGO_REGISTRY_TOKEN" 2>&1 | tee "$log" + local status="${PIPESTATUS[0]}" + set -e + if [ "$status" -eq 0 ]; then + return 0 + fi + if grep -qiE 'already exists|already uploaded' "$log"; then + echo "skip $pkg (already on crates.io)" + return 0 + fi + if grep -qiE 'no matching package named|not found in the registry|try again later|timed out|timeout|503|502|429' "$log"; then + echo "retry $pkg after index/network delay (attempt ${attempt})" + sleep $((attempt * 15)) + continue + fi + echo "::error::cargo publish -p $pkg failed" + return 1 + done + echo "::error::cargo publish -p $pkg failed after retries" + return 1 + } + publish_one amber_transpile + publish_one amber_sandbox + publish_one amberjs diff --git a/Cargo.toml b/Cargo.toml index 22d916bf..03987d77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,51 +13,19 @@ homepage = "https://amberjs.com" documentation = "https://docs.rs/amberjs" keywords = ["javascript", "typescript", "runtime", "v8"] categories = ["command-line-utilities", "development-tools"] +# Whitelist: enough to build the default `amber` binary after `cargo publish`, +# without shipping target/, node_modules/, apps/, or the 46MB benchmarks/ tree. +# `/src/**` is required — lib.rs compiles many modules the old file-by-file +# list omitted, and include_str! also needs src/web_api/*.js plus types/. include = [ "/Cargo.toml", "/Cargo.lock", "/README.md", "/LICENSE", "/build.rs", - "/src/lib.rs", - "/src/napi/*.rs", - "/src/main.rs", - "/src/event_loop.rs", - "/src/runtime_minimal.rs", - "/src/package_manager.rs", - "/src/watcher.rs", - "/src/watcher_websocket.rs", - "/src/ecosystem_lite.rs", - "/src/performance_analyzer.rs", - "/src/performance_comparison.rs", - "/src/performance_regression.rs", - "/src/performance_reporter.rs", - "/src/ai/*.rs", - "/src/ai_inference/*.rs", - "/src/aiops/**/*.rs", - "/src/benchmarks/*.rs", - "/src/cloud_native/**/*.rs", - "/src/error/*.rs", - "/src/fallback/*.rs", - "/src/memory/*.rs", - "/src/monitor/**/*.rs", - "/src/multilang/*.rs", - "/src/nodejs_core/*.rs", - "/src/observability/**/*.rs", - "/src/platform/*.rs", - "/src/security/*.rs", - "/src/testing/**/*.rs", - "/src/typescript/*.rs", - "/src/v8_snapshot/*.rs", - "/src/web_api/*.rs", - "/types/*.d.ts", - "/tests/*.rs", - "/tests/integration/*.rs", - "/examples/basics/*.js", - "/examples/basics/*.ts", - "/examples/testing/*.js", - "/docs/CLI_USAGE_GUIDE.md", - "/docs/QUICK_START.md", + "/src/**", + "/types/**", + "/benches/runtime_startup.rs", ] [workspace] @@ -91,9 +59,9 @@ wasmtime-wasi = "38.0" # WebAssembly bindings wasm-bindgen = "0.2" -# Workspace member crates -amber_transpile = { path = "crates/amber_transpile" } -amber_sandbox = { path = "crates/amber_sandbox" } +# Workspace member crates (path for local builds; version for crates.io) +amber_transpile = { path = "crates/amber_transpile", version = "1.16.0" } +amber_sandbox = { path = "crates/amber_sandbox", version = "1.16.0" } wasm-bindgen-futures = "0.4" # WebAssembly binary format diff --git a/README.md b/README.md index fc3ba9c3..ca297be0 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Release License CI + crates.io

@@ -74,6 +75,12 @@ Homebrew (formula in this repo; SHA256 is rewritten on each GitHub Release): brew install zh30/tap/amber ``` +crates.io (each GitHub `v*` tag publishes via Release Assets + `CARGO_REGISTRY_TOKEN`; install the `amber` binary): + +```sh +cargo install amberjs +``` + ```sh amber --version amber eval "1 + 1" diff --git a/apps/website/src/docs/installation.md b/apps/website/src/docs/installation.md index 04c1c554..b0992301 100644 --- a/apps/website/src/docs/installation.md +++ b/apps/website/src/docs/installation.md @@ -28,6 +28,14 @@ Homebrew (formula in the Amber repo; tap hashes are filled after each GitHub Rel brew install zh30/tap/amber ``` +From crates.io (GitHub `v*` tags publish `amber_transpile`, `amber_sandbox`, then `amberjs` via Release Assets + `CARGO_REGISTRY_TOKEN`): + +```bash +cargo install amberjs +``` + +This installs the `amber` binary. Needs Rust **1.97.1** and a C++ toolchain for V8. + ### What the Install Script Does 1. **Detects Environment**: Automatically identifies your OS (macOS / Linux) and CPU architecture (Apple Silicon `arm64` or Intel `x86_64`). diff --git a/apps/website/src/docs/installation.zh.md b/apps/website/src/docs/installation.zh.md index e60bc175..681faca6 100644 --- a/apps/website/src/docs/installation.zh.md +++ b/apps/website/src/docs/installation.zh.md @@ -28,6 +28,14 @@ Homebrew(配方在 Amber 仓库内;每次 GitHub Release 后填写 sha256) brew install zh30/tap/amber ``` +crates.io(GitHub `v*` 标签通过 Release Assets + `CARGO_REGISTRY_TOKEN` 按 `amber_transpile` → `amber_sandbox` → `amberjs` 发布): + +```bash +cargo install amberjs +``` + +会安装 `amber` 二进制。需要 Rust **1.97.1** 以及编译 V8 的 C++ 工具链。 + ### 安装脚本执行过程说明 1. **自动识别硬件与系统**:自动检测你的系统(macOS / Linux)与 CPU 架构(Apple Silicon `arm64`、Intel `x86_64`); diff --git a/crates/amber_sandbox/Cargo.toml b/crates/amber_sandbox/Cargo.toml index 0f2a819b..c195af97 100644 --- a/crates/amber_sandbox/Cargo.toml +++ b/crates/amber_sandbox/Cargo.toml @@ -2,8 +2,15 @@ name = "amber_sandbox" version = "1.16.0" edition = "2021" +authors = ["Henry Zhang"] description = "Capability sandbox and in-memory virtual filesystem for Amber runtime" license = "MIT" +readme = "README.md" +repository = "https://github.com/zh30/amberjs" +homepage = "https://amberjs.com" +documentation = "https://docs.rs/amber_sandbox" +keywords = ["sandbox", "vfs", "permissions"] +categories = ["development-tools"] [dependencies] once_cell = "1.0" diff --git a/crates/amber_sandbox/README.md b/crates/amber_sandbox/README.md new file mode 100644 index 00000000..8d56bc85 --- /dev/null +++ b/crates/amber_sandbox/README.md @@ -0,0 +1,9 @@ +# amber_sandbox + +Capability sandbox and in-memory virtual filesystem used by the [Amber](https://github.com/zh30/amberjs) runtime (`--sandbox`, permission policy, deterministic VFS). + +Published as a workspace crate so `amberjs` can be released to crates.io. The CLI users want is: + +```sh +cargo install amberjs +``` diff --git a/crates/amber_transpile/Cargo.toml b/crates/amber_transpile/Cargo.toml index 08d25d13..29e28a4e 100644 --- a/crates/amber_transpile/Cargo.toml +++ b/crates/amber_transpile/Cargo.toml @@ -2,8 +2,15 @@ name = "amber_transpile" version = "1.16.0" edition = "2021" +authors = ["Henry Zhang"] description = "Fast TypeScript transpile and bundling engine for Amber runtime" license = "MIT" +readme = "README.md" +repository = "https://github.com/zh30/amberjs" +homepage = "https://amberjs.com" +documentation = "https://docs.rs/amber_transpile" +keywords = ["javascript", "typescript", "transpile"] +categories = ["development-tools"] [dependencies] oxc = { version = "0.147", default-features = false, features = [ diff --git a/crates/amber_transpile/README.md b/crates/amber_transpile/README.md new file mode 100644 index 00000000..72b416f6 --- /dev/null +++ b/crates/amber_transpile/README.md @@ -0,0 +1,9 @@ +# amber_transpile + +TypeScript/TSX transpile engine for the [Amber](https://github.com/zh30/amberjs) runtime. It uses [oxc](https://oxc.rs/) and is transpile-only (no `tsc` typecheck). + +Published as a workspace crate so `amberjs` can be released to crates.io. The CLI users want is: + +```sh +cargo install amberjs +``` diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index eddfdb37..6c4578b6 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -596,6 +596,8 @@ pub fn execute_string(&self, code: &str) -> Result { - [ ] 更新 CHANGELOG.md - [ ] 创建 GitHub Release +3. **crates.io**: 打 `v*` 标签(或对已有标签跑 Release Assets 的 `workflow_dispatch`)。GitHub Release / Homebrew / cosign 完成后,同一 job 用仓库 secret `CARGO_REGISTRY_TOKEN` 按 `amber_transpile` → `amber_sandbox` → `amberjs` 发布。token 为空则跳过并打 warning。用户安装:`cargo install amberjs`(二进制名 `amber`)。 + ## 📞 获取帮助 如果您需要帮助,可以通过以下方式联系我们: diff --git a/docs/GITHUB_ACTIONS_RUNTIME_INFRASTRUCTURE.md b/docs/GITHUB_ACTIONS_RUNTIME_INFRASTRUCTURE.md index aa46edde..c8579f59 100644 --- a/docs/GITHUB_ACTIONS_RUNTIME_INFRASTRUCTURE.md +++ b/docs/GITHUB_ACTIONS_RUNTIME_INFRASTRUCTURE.md @@ -9,7 +9,7 @@ PR gates, multi-OS GitHub Releases (including Windows zip), GHCR publish, SBOM/c | Workflow file | Trigger | What it actually does | |---|---|---| | `.github/workflows/ci.yml` | `push` `main`, PR → `main`, `workflow_dispatch`, `v*` | rustc **1.97.1**, fmt, clippy `-D warnings`, `cargo test`, feature matrix `benchmarks` + `observability` (fail-closed), WinterTC named step, Node conformance, `amber test examples/testing`, `cargo package --list`, ubuntu + macOS release smoke, Windows smoke, **cargo-audit fail-closed**, cargo-deny advisories/licenses | -| `.github/workflows/release-assets.yml` | `v*` tags, `workflow_dispatch` | linux gnu x64/arm64, macOS arm64/x64, Windows x64 zip (**no** `continue-on-error` on Windows); requires Unix archives **and** Windows zip with `amber.exe`; checksums, CycloneDX SBOM, cosign; Homebrew formula SHA rewrite | +| `.github/workflows/release-assets.yml` | `v*` tags, `workflow_dispatch` | linux gnu x64/arm64, macOS arm64/x64, Windows x64 zip (**no** `continue-on-error` on Windows); requires Unix archives **and** Windows zip with `amber.exe`; checksums, CycloneDX SBOM, cosign; Homebrew formula SHA rewrite; crates.io publish of `amber_transpile` → `amber_sandbox` → `amberjs` when `CARGO_REGISTRY_TOKEN` is set | | `.github/workflows/docker.yml` | `main`, `v*`, `workflow_dispatch` | Build/push `ghcr.io/zh30/amberjs` **linux/amd64 only** (no fake `linux/arm64` tag) | | `.github/workflows/performance-tests.yml` | Monday 02:00 UTC cron, `workflow_dispatch` | Release lib benchmark tests. Not a PR gate | @@ -18,7 +18,7 @@ PR gates, multi-OS GitHub Releases (including Windows zip), GHCR publish, SBOM/c - GHCR is **amd64-only**. - `feature = "ai"` is empty and is not in the CI matrix; default `amber:ai` compiles without it. - `enterprise` / `cloudnative` / `multilang` / `tch` are not CI-gated. -- crates.io publish is skipped without `CARGO_REGISTRY_TOKEN`. +- crates.io publish is skipped without `CARGO_REGISTRY_TOKEN` (warning annotation). With the token, Release Assets publishes workspace crates in dependency order; already-uploaded versions are skipped. - Live tag, brew checksum against a published Release, and `microsoft/winget-pkgs` submission are out of band. See [IMPLEMENTATION_PLAN_v1.9.1.md](./IMPLEMENTATION_PLAN_v1.9.1.md) and [INFRASTRUCTURE_CAPABILITY_BACKLOG.md](./INFRASTRUCTURE_CAPABILITY_BACKLOG.md). diff --git a/tests/release_workflow_tests.rs b/tests/release_workflow_tests.rs index e0dfa9ad..4d64dc86 100644 --- a/tests/release_workflow_tests.rs +++ b/tests/release_workflow_tests.rs @@ -83,6 +83,170 @@ fn tag_v_star_publishes_non_draft_release_with_five_amber_archives() { ); } +fn first_package_version(toml: &str) -> &str { + let package = toml + .split("[package]") + .nth(1) + .expect("[package] table") + .split('[') + .next() + .expect("package fields"); + package + .lines() + .find_map(|line| { + let line = line.trim(); + line.strip_prefix("version = \"") + .and_then(|rest| rest.strip_suffix('"')) + }) + .expect("package version") +} + +#[test] +fn workspace_path_deps_have_crates_io_versions_matching_members() { + let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let root = fs::read_to_string(manifest.join("Cargo.toml")).unwrap(); + let transpile = fs::read_to_string(manifest.join("crates/amber_transpile/Cargo.toml")).unwrap(); + let sandbox = fs::read_to_string(manifest.join("crates/amber_sandbox/Cargo.toml")).unwrap(); + let zed = fs::read_to_string(manifest.join("extensions/zed/Cargo.toml")).unwrap(); + + let root_ver = first_package_version(&root); + let transpile_ver = first_package_version(&transpile); + let sandbox_ver = first_package_version(&sandbox); + assert_eq!( + root_ver, transpile_ver, + "amber_transpile version must match root" + ); + assert_eq!( + root_ver, sandbox_ver, + "amber_sandbox version must match root" + ); + assert!( + root.contains(&format!( + "amber_transpile = {{ path = \"crates/amber_transpile\", version = \"{root_ver}\" }}" + )), + "root must depend on amber_transpile with path + version for cargo publish: {root}" + ); + assert!( + root.contains(&format!( + "amber_sandbox = {{ path = \"crates/amber_sandbox\", version = \"{root_ver}\" }}" + )), + "root must depend on amber_sandbox with path + version for cargo publish: {root}" + ); + + for (name, toml) in [("amber_transpile", &transpile), ("amber_sandbox", &sandbox)] { + assert!( + toml.contains("license = \"MIT\""), + "{name} must declare MIT license" + ); + assert!( + toml.contains("repository = \"https://github.com/zh30/amberjs\""), + "{name} must declare the GitHub repository for crates.io" + ); + assert!( + toml.contains("description = \""), + "{name} must have a crates.io description" + ); + assert!( + !toml.contains("publish = false"), + "{name} must be publishable" + ); + } + assert!( + zed.contains("publish = false"), + "Zed extension must not be published to crates.io" + ); +} + +#[test] +fn cargo_package_include_covers_src_and_types_not_huge_trees() { + let cargo = + fs::read_to_string(PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml")).unwrap(); + let include = cargo + .split("include = [") + .nth(1) + .and_then(|rest| rest.split(']').next()) + .expect("include list"); + assert!( + include.contains("/src/**"), + "include must ship the whole src tree so the published crate builds: {include}" + ); + assert!( + include.contains("/types/**") || include.contains("/types/*.d.ts"), + "include must ship types/ for include_str!(amberjs.d.ts): {include}" + ); + assert!( + include.contains("/build.rs") && include.contains("/Cargo.lock"), + "published package must include build.rs and Cargo.lock: {include}" + ); + for banned in [ + "node_modules", + "benchmarks/", + "/apps/", + "/target/", + "/docs/STAGE_", + ] { + assert!( + !include.contains(banned), + "include must not whitelist {banned}: {include}" + ); + } +} + +#[test] +fn crates_io_publish_is_ordered_and_idempotent_after_github_release() { + let yaml = release_assets_yaml(); + let release_at = yaml + .find("uses: softprops/action-gh-release") + .expect("GitHub Release step"); + let publish_at = yaml + .find("Publish to crates.io") + .expect("crates.io publish step"); + assert!( + publish_at > release_at, + "crates.io publish must run after action-gh-release" + ); + let publish = &yaml[publish_at..]; + let transpile = publish + .find("amber_transpile") + .expect("publish amber_transpile"); + let sandbox = publish + .find("amber_sandbox") + .expect("publish amber_sandbox"); + let root = publish + .find("publish_one amberjs") + .or_else(|| publish.find("-p amberjs")) + .expect("publish amberjs"); + assert!( + transpile < sandbox && sandbox < root, + "publish order must be amber_transpile, amber_sandbox, amberjs" + ); + assert!( + publish.contains("already exists") && publish.contains("already uploaded"), + "re-running a tag must skip versions already on crates.io" + ); + assert!( + publish.contains("--locked") && publish.contains("--token"), + "cargo publish must use --locked and CARGO_REGISTRY_TOKEN" + ); + assert!( + publish.contains("CARGO_REGISTRY_TOKEN"), + "publish must use the existing CARGO_REGISTRY_TOKEN secret" + ); + assert!( + !publish.contains("zed-amberjs"), + "Zed extension crate must not be published" + ); + let publish_step = yaml.split("Publish to crates.io").nth(1).unwrap_or(""); + let publish_step = publish_step + .split("\n - name:") + .next() + .unwrap_or(publish_step); + assert!( + !publish_step.contains("continue-on-error"), + "crates.io publish must fail the job when the registry is down" + ); +} + #[test] fn homebrew_formula_push_must_not_block_github_release() { let yaml = release_assets_yaml(); From 3fcf8190b9acae7c8a8b5a9a7ee7ec61f7b299fb Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 20 Sep 2026 14:46:49 +0000 Subject: [PATCH 2/2] =?UTF-8?q?docs(v1.16.0):=20=E8=AF=B4=E6=98=8E=20amber?= =?UTF-8?q?js=20dry-run=20=E4=BE=9D=E8=B5=96=20crates.io=20=E6=88=90?= =?UTF-8?q?=E5=91=98=20crate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本地 cargo publish --dry-run -p amberjs 在 amber_transpile / amber_sandbox 尚未上架时无法解析 version 依赖;Release Assets 会先发布这两个成员。 Co-authored-by: Henry Zhang --- Cargo.toml | 4 +++- docs/CONTRIBUTING.md | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 03987d77..00a967ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,9 @@ wasmtime-wasi = "38.0" # WebAssembly bindings wasm-bindgen = "0.2" -# Workspace member crates (path for local builds; version for crates.io) +# Workspace member crates (path for local builds; version for crates.io). +# `cargo publish -p amberjs --dry-run` cannot resolve these until the same +# versions exist on crates.io; Release Assets publishes the members first. amber_transpile = { path = "crates/amber_transpile", version = "1.16.0" } amber_sandbox = { path = "crates/amber_sandbox", version = "1.16.0" } wasm-bindgen-futures = "0.4" diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 6c4578b6..7d083216 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -596,7 +596,7 @@ pub fn execute_string(&self, code: &str) -> Result { - [ ] 更新 CHANGELOG.md - [ ] 创建 GitHub Release -3. **crates.io**: 打 `v*` 标签(或对已有标签跑 Release Assets 的 `workflow_dispatch`)。GitHub Release / Homebrew / cosign 完成后,同一 job 用仓库 secret `CARGO_REGISTRY_TOKEN` 按 `amber_transpile` → `amber_sandbox` → `amberjs` 发布。token 为空则跳过并打 warning。用户安装:`cargo install amberjs`(二进制名 `amber`)。 +3. **crates.io**: 打 `v*` 标签(或对已有标签跑 Release Assets 的 `workflow_dispatch`)。GitHub Release / Homebrew / cosign 完成后,同一 job 用仓库 secret `CARGO_REGISTRY_TOKEN` 按 `amber_transpile` → `amber_sandbox` → `amberjs` 发布。token 为空则跳过并打 warning。用户安装:`cargo install amberjs`(二进制名 `amber`)。本地可 `cargo publish -p amber_transpile --dry-run` / `amber_sandbox`;根包 `amberjs` 的 dry-run 要等这两个 crate 的同一版本已在 crates.io 上(cargo 按 version 解析,工作流会先发布成员)。 ## 📞 获取帮助