mirror of
https://github.com/eth-act/ere.git
synced 2026-02-19 11:54:42 -05:00
Auto zkvm update check (#186)
This commit is contained in:
58
.github/scripts/fetch-zkvm-version.sh
vendored
Executable file
58
.github/scripts/fetch-zkvm-version.sh
vendored
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
# Usage: ./fetch-zkvm-version.sh <zkvm> <crate>
|
||||
# Examples:
|
||||
# .github/scripts/fetch-zkvm-version.sh airbender execution_utils
|
||||
# .github/scripts/fetch-zkvm-version.sh jolt jolt-sdk
|
||||
# .github/scripts/fetch-zkvm-version.sh miden miden-core
|
||||
# .github/scripts/fetch-zkvm-version.sh nexus nexus-sdk
|
||||
# .github/scripts/fetch-zkvm-version.sh openvm openvm-sdk
|
||||
# .github/scripts/fetch-zkvm-version.sh pico pico-vm
|
||||
# .github/scripts/fetch-zkvm-version.sh risc0 risc0-zkvm
|
||||
# .github/scripts/fetch-zkvm-version.sh sp1 sp1-sdk
|
||||
# .github/scripts/fetch-zkvm-version.sh ziren zkm-sdk
|
||||
# .github/scripts/fetch-zkvm-version.sh zisk 0xPolygonHermez/zisk
|
||||
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "Usage: $0 <zkvm> <crate>"
|
||||
echo " crate: crate (e.g. openvm-sdk) or github org/repo (e.g. 0xPolygonHermez/zisk)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ZKVM=$1
|
||||
CRATE=$2
|
||||
|
||||
get_github_latest() {
|
||||
local org_repo=$1
|
||||
curl -sL "https://api.github.com/repos/$org_repo/tags" | grep -oP '"name":\s*"\K[^"]+' | head -1
|
||||
}
|
||||
|
||||
get_crates_io_latest() {
|
||||
local crate=$1
|
||||
curl -sL -A "EreCI" "https://crates.io/api/v1/crates/$crate" | grep -oP '"max_version":"\K[^"]+'
|
||||
}
|
||||
|
||||
if [[ "$CRATE" == */* ]]; then
|
||||
# It is in format of org/repo, get current version from build.rs
|
||||
LATEST=$(get_github_latest "$CRATE")
|
||||
CURRENT=$(grep -oP 'gen_name_and_sdk_version\("'"$ZKVM"'", "\K[^"]+' "crates/zkvm/$ZKVM/build.rs")
|
||||
else
|
||||
# It is a crate name, get current version from Cargo.toml
|
||||
LINE=$(grep "$CRATE" Cargo.toml)
|
||||
|
||||
if echo "$LINE" | grep -q "git ="; then
|
||||
# Dependency from github.com
|
||||
REPO=$(echo "$LINE" | grep -oP 'git = "https://github.com/\K[^"]+' | sed 's/\.git$//')
|
||||
CURRENT=$(echo "$LINE" | grep -oP 'tag = "\K[^"]+')
|
||||
LATEST=$(get_github_latest "$REPO")
|
||||
else
|
||||
# Dependency from crates.io
|
||||
CURRENT=$(grep "^$CRATE = " Cargo.toml | grep -oP '"\K[0-9.]+(?=")')
|
||||
LATEST=$(get_crates_io_latest "$CRATE")
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "CURRENT=v${CURRENT#v}"
|
||||
echo "LATEST=v${LATEST#v}"
|
||||
131
.github/workflows/check-zkvm-version.yml
vendored
Normal file
131
.github/workflows/check-zkvm-version.yml
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
name: Check zkVM version
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run every day at 00:00 UTC
|
||||
- cron: '0 0 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-zkvm-version:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- zkvm: airbender
|
||||
crate: execution_utils
|
||||
- zkvm: jolt
|
||||
crate: jolt-sdk
|
||||
- zkvm: miden
|
||||
crate: miden-core
|
||||
- zkvm: nexus
|
||||
crate: nexus-sdk
|
||||
- zkvm: openvm
|
||||
crate: openvm-sdk
|
||||
- zkvm: pico
|
||||
crate: pico-vm
|
||||
- zkvm: risc0
|
||||
crate: risc0-zkvm
|
||||
- zkvm: sp1
|
||||
crate: sp1-sdk
|
||||
- zkvm: ziren
|
||||
crate: zkm-sdk
|
||||
- zkvm: zisk
|
||||
crate: 0xPolygonHermez/zisk
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check ${{ matrix.zkvm }} version
|
||||
id: check
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -e -o pipefail
|
||||
|
||||
RESULT=$(.github/scripts/fetch-zkvm-version.sh "${{ matrix.zkvm }}" "${{ matrix.crate }}")
|
||||
|
||||
CURRENT=$(echo "$RESULT" | grep "CURRENT=" | cut -d= -f2)
|
||||
LATEST=$(echo "$RESULT" | grep "LATEST=" | cut -d= -f2)
|
||||
|
||||
if [ -z "$CURRENT" ] || [ -z "$LATEST" ]; then
|
||||
echo "Failed to fetch version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "current=$CURRENT" >> $GITHUB_OUTPUT
|
||||
echo "latest=$LATEST" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "Current version: $CURRENT"
|
||||
echo "Latest version: $LATEST"
|
||||
|
||||
if [ "$CURRENT" == "$LATEST" ]; then
|
||||
echo "Up to date"
|
||||
echo "outdated=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "Update available"
|
||||
echo "outdated=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Create or update issue if outdated
|
||||
if: steps.check.outputs.outdated == 'true'
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
ZKVM: ${{ matrix.zkvm }}
|
||||
CURRENT: ${{ steps.check.outputs.current }}
|
||||
LATEST: ${{ steps.check.outputs.latest }}
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const zkvm = process.env.ZKVM;
|
||||
const current = process.env.CURRENT;
|
||||
const latest = process.env.LATEST;
|
||||
|
||||
const title = `Update \`${zkvm}\` to \`${latest}\``;
|
||||
const body = `
|
||||
A new version of \`${zkvm}\` is available.
|
||||
|
||||
- Current version: \`${current}\`
|
||||
- Latest version: \`${latest}\`
|
||||
`;
|
||||
|
||||
const issues = await github.rest.issues.listForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
labels: `zkvm:${zkvm}`,
|
||||
per_page: 100
|
||||
});
|
||||
|
||||
const existingIssue = issues.data.find(issue =>
|
||||
issue.title.startsWith(`Update \`${zkvm}\` to`)
|
||||
);
|
||||
|
||||
if (existingIssue) {
|
||||
if (existingIssue.title === title) {
|
||||
console.log(`Issue #${existingIssue.number} already exists`);
|
||||
} else {
|
||||
await github.rest.issues.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: existingIssue.number,
|
||||
body: body.trim(),
|
||||
title
|
||||
});
|
||||
console.log(`Updated issue #${existingIssue.number} with new version ${latest}`);
|
||||
}
|
||||
} else {
|
||||
const issue = await github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title,
|
||||
body: body.trim(),
|
||||
labels: [`zkvm:${zkvm}`]
|
||||
});
|
||||
console.log(`Created issue #${issue.data.number}`);
|
||||
}
|
||||
2
.github/workflows/test-zkvm.yml
vendored
2
.github/workflows/test-zkvm.yml
vendored
@@ -173,7 +173,7 @@ jobs:
|
||||
/bin/bash"
|
||||
|
||||
cat <<EOF | $DOCKER_CMD
|
||||
set -e
|
||||
set -e -o pipefail
|
||||
|
||||
OPTIONS="--all-targets -- -D warnings"
|
||||
cargo clippy --package ere-${{ inputs.zkvm }} \$OPTIONS
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -3748,8 +3748,6 @@ name = "ere-build-utils"
|
||||
version = "0.0.14"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.19.2",
|
||||
"thiserror 2.0.12",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -6,9 +6,7 @@ rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
tracing.workspace = true
|
||||
cargo_metadata.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use thiserror::Error;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("Invalid Dockerfile path: {0}")]
|
||||
InvalidDockerfilePath(PathBuf),
|
||||
#[error("Docker image build failed: {0}")]
|
||||
DockerBuildFailed(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
#[error("Docker image build failed")]
|
||||
ImageBuildFailed,
|
||||
#[error("Docker is not available. Please ensure Docker is installed and running.")]
|
||||
DockerIsNotAvailable,
|
||||
}
|
||||
|
||||
pub fn build_image(compiler_dockerfile: &Path, tag: &str) -> Result<(), Error> {
|
||||
// Check that Docker is installed and available
|
||||
if Command::new("docker")
|
||||
.arg("--version")
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.status()
|
||||
.is_err()
|
||||
{
|
||||
return Err(Error::DockerIsNotAvailable);
|
||||
}
|
||||
|
||||
info!(
|
||||
"Building Docker image in {} with tag {}",
|
||||
compiler_dockerfile.display(),
|
||||
tag
|
||||
);
|
||||
|
||||
let cargo_workspace_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../..")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
|
||||
// Build base image
|
||||
info!("Building base Docker image...");
|
||||
let dockerfile_base_path = cargo_workspace_dir.join("docker/base/Dockerfile.base");
|
||||
let status = Command::new("docker")
|
||||
.args([
|
||||
"build",
|
||||
"-t",
|
||||
"ere-base:latest",
|
||||
"-f",
|
||||
dockerfile_base_path
|
||||
.to_str()
|
||||
.ok_or_else(|| Error::InvalidDockerfilePath(dockerfile_base_path.clone()))?,
|
||||
cargo_workspace_dir.to_str().unwrap(),
|
||||
])
|
||||
.status()
|
||||
.map_err(|e| Error::DockerBuildFailed(e.into()))?;
|
||||
if !status.success() {
|
||||
return Err(Error::ImageBuildFailed);
|
||||
}
|
||||
|
||||
info!("Building guest compiler image...");
|
||||
let dockerfile_path = cargo_workspace_dir.join(compiler_dockerfile);
|
||||
let status = Command::new("docker")
|
||||
.args([
|
||||
"build",
|
||||
"-t",
|
||||
tag,
|
||||
"-f",
|
||||
dockerfile_path
|
||||
.to_str()
|
||||
.ok_or_else(|| Error::InvalidDockerfilePath(dockerfile_path.clone()))?,
|
||||
cargo_workspace_dir.to_str().unwrap(),
|
||||
])
|
||||
.status()
|
||||
.map_err(|e| Error::DockerBuildFailed(e.into()))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(Error::ImageBuildFailed);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DockerRunCommand {
|
||||
image: String,
|
||||
volumes: Vec<(String, String)>, // (host_path, container_path)
|
||||
command: Vec<String>,
|
||||
// remove image after running
|
||||
remove_after: bool,
|
||||
}
|
||||
|
||||
impl DockerRunCommand {
|
||||
pub fn new(image: impl Into<String>) -> Self {
|
||||
Self {
|
||||
image: image.into(),
|
||||
volumes: Vec::new(),
|
||||
command: Vec::new(),
|
||||
remove_after: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_volume(
|
||||
mut self,
|
||||
host_path: impl Into<String>,
|
||||
container_path: impl Into<String>,
|
||||
) -> Self {
|
||||
self.volumes.push((host_path.into(), container_path.into()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_command(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
|
||||
self.command.extend(args.into_iter().map(|s| s.into()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn remove_after_run(mut self) -> Self {
|
||||
self.remove_after = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn to_args(&self) -> Vec<String> {
|
||||
let mut args = vec!["run".to_string()];
|
||||
|
||||
if self.remove_after {
|
||||
args.push("--rm".to_string());
|
||||
}
|
||||
|
||||
for (host_path, container_path) in &self.volumes {
|
||||
args.extend(["-v".to_string(), format!("{host_path}:{container_path}")]);
|
||||
}
|
||||
|
||||
args.push(self.image.clone());
|
||||
args.extend(self.command.iter().cloned());
|
||||
|
||||
args
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Result<std::process::ExitStatus, std::io::Error> {
|
||||
Command::new("docker").args(self.to_args()).status()
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
use cargo_metadata::MetadataCommand;
|
||||
use std::{env, fs, path::Path};
|
||||
|
||||
pub mod docker;
|
||||
|
||||
// Detect and generate a Rust source file that contains the name and version of the SDK.
|
||||
pub fn detect_and_generate_name_and_sdk_version(name: &str, sdk_dep_name: &str) {
|
||||
gen_name_and_sdk_version(name, &detect_sdk_version(sdk_dep_name));
|
||||
|
||||
Reference in New Issue
Block a user