Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ocvm"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
description = "OpenClaw Version Manager"
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ Rollback does not delete unrelated installed versions.
After a GitHub Release exists:

```bash
curl -fsSL https://raw.githubusercontent.com/PerfectPan/ocvm/main/install.sh | sh
curl -fsSL https://raw.githubusercontent.com/PerfectPan/ocvm/v0.1.1/install.sh | sh
```

## Docker E2E
Expand Down
14 changes: 10 additions & 4 deletions docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,24 @@ cargo package --allow-dirty
3. Create and push a version tag:

```bash
git tag v0.1.0
git push origin v0.1.0
git tag v0.1.1
git push origin v0.1.1
```

The `Release` workflow builds platform binaries, packages archives, generates SHA256 checksum files, and creates a GitHub Release.

## Install Script

Users can install the latest release with:
Users can install a specific release with:

```bash
curl -fsSL https://raw.githubusercontent.com/PerfectPan/ocvm/main/install.sh | sh
curl -fsSL https://raw.githubusercontent.com/PerfectPan/ocvm/v0.1.1/install.sh | sh
```

Override `OCVM_VERSION` to install a different release:

```bash
curl -fsSL https://raw.githubusercontent.com/PerfectPan/ocvm/v0.1.1/install.sh | OCVM_VERSION=latest sh
```

## Docker E2E
Expand Down
12 changes: 10 additions & 2 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ set -eu
REPO="${OCVM_REPO:-PerfectPan/ocvm}"
INSTALL_DIR="${OCVM_INSTALL_DIR:-$HOME/.local/bin}"
API_BASE="${GITHUB_API_URL:-https://api.github.com}"
INSTALLER_VERSION="v0.1.1"
VERSION="${OCVM_VERSION:-$INSTALLER_VERSION}"

need() {
command -v "$1" >/dev/null 2>&1 || {
Expand Down Expand Up @@ -40,12 +42,19 @@ esac
target="${arch}-${os}"
asset="ocvm-${target}.tar.gz"

if [ "$VERSION" = "latest" ]; then
api_url="${API_BASE}/repos/${REPO}/releases/latest"
else
api_url="${API_BASE}/repos/${REPO}/releases/tags/${VERSION}"
fi

if [ "${OCVM_INSTALL_DRY_RUN:-}" = "1" ]; then
cat <<EOF
repo=${REPO}
version=${VERSION}
target=${target}
asset=${asset}
api_url=${API_BASE}/repos/${REPO}/releases/latest
api_url=${api_url}
install_dir=${INSTALL_DIR}
EOF
exit 0
Expand All @@ -60,7 +69,6 @@ if [ -n "${GITHUB_TOKEN:-}" ]; then
auth_header="Authorization: Bearer ${GITHUB_TOKEN}"
fi

api_url="${API_BASE}/repos/${REPO}/releases/latest"
release_json="$tmp/release.json"

if [ -n "$auth_header" ]; then
Expand Down
3 changes: 3 additions & 0 deletions scripts/check-release-prep.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ expect_output "asset=ocvm-x86_64-apple-darwin.tar.gz" \
expect_output "asset=ocvm-aarch64-apple-darwin.tar.gz" \
env OCVM_INSTALL_DRY_RUN=1 OCVM_TEST_UNAME_S=Darwin OCVM_TEST_UNAME_M=arm64 ./install.sh

expect_output "api_url=https://api.github.com/repos/PerfectPan/ocvm/releases/tags/v0.1.1" \
env OCVM_INSTALL_DRY_RUN=1 OCVM_VERSION=v0.1.1 OCVM_TEST_UNAME_S=Darwin OCVM_TEST_UNAME_M=arm64 ./install.sh

expect_file_text .github/workflows/release.yml "target: x86_64-unknown-linux-gnu"
expect_file_text .github/workflows/release.yml "target: x86_64-apple-darwin"
expect_file_text .github/workflows/release.yml "target: aarch64-apple-darwin"
Expand Down
4 changes: 2 additions & 2 deletions site/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ OpenClaw 2026.3.28`}</pre>
<section id="install" className="installBand">
<div>
<p className="sectionLabel">Install</p>
<h2>One command once the first GitHub Release is published.</h2>
<h2>Install a pinned release with one command.</h2>
</div>
<pre className="installCommand">
curl -fsSL https://raw.githubusercontent.com/PerfectPan/ocvm/main/install.sh | sh
curl -fsSL https://raw.githubusercontent.com/PerfectPan/ocvm/v0.1.1/install.sh | sh
</pre>
</section>

Expand Down
26 changes: 17 additions & 9 deletions tests/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use assert_cmd::Command;
use predicates::prelude::*;
use std::{fs, path::PathBuf};
use std::{fs, io::Write, path::PathBuf};
use tempfile::TempDir;

fn cmd(home: &TempDir) -> Command {
Expand All @@ -26,6 +26,21 @@ fn fake_openclaw_body(output: &str) -> String {
}
}

fn write_fake_openclaw(path: &PathBuf, output: &str) {
let mut file = fs::File::create(path).unwrap();
file.write_all(fake_openclaw_body(output).as_bytes())
.unwrap();
file.sync_all().unwrap();
drop(file);
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut permissions = fs::metadata(path).unwrap().permissions();
permissions.set_mode(0o755);
fs::set_permissions(path, permissions).unwrap();
}
}

fn install_fake(home: &TempDir, version: &str, output: &str) {
let bin = home
.path()
Expand All @@ -36,14 +51,7 @@ fn install_fake(home: &TempDir, version: &str, output: &str) {
.join(".bin");
fs::create_dir_all(&bin).unwrap();
let openclaw = fake_openclaw_path(bin);
fs::write(&openclaw, fake_openclaw_body(output)).unwrap();
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut permissions = fs::metadata(&openclaw).unwrap().permissions();
permissions.set_mode(0o755);
fs::set_permissions(openclaw, permissions).unwrap();
}
write_fake_openclaw(&openclaw, output);
}

#[test]
Expand Down
25 changes: 17 additions & 8 deletions tests/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ocvm::source::{RemoteVersion, SourceProvider};
use ocvm::version;
use std::cell::RefCell;
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use tempfile::TempDir;

Expand Down Expand Up @@ -62,6 +63,21 @@ fn fake_openclaw_body(output: &str) -> String {
}
}

fn write_fake_openclaw(path: &Path, output: &str) -> Result<()> {
let mut file = fs::File::create(path)?;
file.write_all(fake_openclaw_body(output).as_bytes())?;
file.sync_all()?;
drop(file);
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut permissions = fs::metadata(path)?.permissions();
permissions.set_mode(0o755);
fs::set_permissions(path, permissions)?;
}
Ok(())
}

impl SourceProvider for FakeSource {
fn resolve_alias(&self, requested: &str) -> Result<String> {
Ok(self
Expand Down Expand Up @@ -102,14 +118,7 @@ impl SourceProvider for FakeSource {
let bin = staging_dir.join("node_modules").join(".bin");
fs::create_dir_all(&bin)?;
let openclaw = fake_openclaw_path(bin);
fs::write(&openclaw, fake_openclaw_body(version))?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let mut permissions = fs::metadata(&openclaw)?.permissions();
permissions.set_mode(0o755);
fs::set_permissions(openclaw, permissions)?;
}
write_fake_openclaw(&openclaw, version)?;
Ok(())
}

Expand Down
Loading