diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..ec89970 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,77 @@ +name: Build and Publish Docker Image + +on: + push: + branches: [main] + tags: ['v*'] + pull_request: + branches: [main] + paths: + - 'Dockerfile' + - '.github/workflows/docker-publish.yml' + - 'src/**' + - 'Cargo.toml' + - 'Cargo.lock' + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha,prefix=,suffix=,format=short + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + target: release + + - name: Build dev image + uses: docker/build-push-action@v5 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:dev + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + target: dev diff --git a/docker-compose.yml b/docker-compose.yml index 07f777d..5eec787 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,9 +9,13 @@ services: zerobuild: - image: ghcr.io/zerobuild-labs/zerobuild:latest + image: ghcr.io/potlock/zerobuild:latest # Or build locally: # build: . + # Or use dev target: + # build: + # context: . + # target: dev container_name: zerobuild restart: unless-stopped diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..498a0ca --- /dev/null +++ b/install.sh @@ -0,0 +1,277 @@ +#!/usr/bin/env bash +# +# ZeroBuild One-Click Installer +# +# Install ZeroBuild quickly using: +# curl -fsSL https://raw.githubusercontent.com/PotLock/zerobuild/main/install.sh | bash +# +# Or with wget: +# wget -qO- https://raw.githubusercontent.com/PotLock/zerobuild/main/install.sh | bash + +set -euo pipefail + +REPO="PotLock/zerobuild" +REGISTRY="ghcr.io" +IMAGE="$REGISTRY/$REPO" +INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}" + +info() { + echo -e "\033[34m==>\033[0m $*" +} + +error() { + echo -e "\033[31merror:\033[0m $*" >&2 +} + +success() { + echo -e "\033[32m✓\033[0m $*" +} + +have_cmd() { + command -v "$1" >/dev/null 2>&1 +} + +detect_platform() { + local os arch + os="$(uname -s | tr '[:upper:]' '[:lower:]')" + arch="$(uname -m)" + + case "$os:$arch" in + linux:x86_64) + echo "linux-amd64" + ;; + linux:aarch64|linux:arm64) + echo "linux-arm64" + ;; + darwin:x86_64) + echo "darwin-amd64" + ;; + darwin:arm64|darwin:aarch64) + echo "darwin-arm64" + ;; + *) + echo "" + ;; + esac +} + +install_docker() { + info "Installing ZeroBuild via Docker..." + + if ! have_cmd docker && ! have_cmd podman; then + error "Docker or Podman is required but not installed." + error "Please install Docker: https://docs.docker.com/get-docker/" + exit 1 + fi + + local container_cmd="docker" + if ! have_cmd docker && have_cmd podman; then + container_cmd="podman" + info "Using Podman instead of Docker" + fi + + # Pull the latest image + info "Pulling ZeroBuild image from GitHub Container Registry..." + $container_cmd pull "$IMAGE:latest" + + # Create data directory + local data_dir="$HOME/.zerobuild" + mkdir -p "$data_dir"/{workspace,.zerobuild} + + # Create wrapper script + cat > "$INSTALL_DIR/zerobuild" <" + info "Example: zerobuild --help" + + # Check if in PATH + if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then + info "" + info "Add to your PATH:" + echo "export PATH=\"$INSTALL_DIR:\$PATH\"" + info "Or run: echo 'export PATH=\"$INSTALL_DIR:\$PATH\"' >> ~/.bashrc" + fi +} + +install_binary() { + local platform="$(detect_platform)" + + if [[ -z "$platform" ]]; then + error "Unsupported platform: $(uname -s) $(uname -m)" + error "Try Docker installation instead:" + echo " curl -fsSL https://raw.githubusercontent.com/$REPO/main/install.sh | bash -s -- --docker" + exit 1 + fi + + info "Installing ZeroBuild binary for $platform..." + + # Create temp directory + local tmp_dir="$(mktemp -d)" + trap "rm -rf $tmp_dir" EXIT + + # Download binary + local download_url="https://github.com/$REPO/releases/latest/download/zerobuild-$platform.tar.gz" + info "Downloading from $download_url..." + + if ! curl -fsSL "$download_url" -o "$tmp_dir/zerobuild.tar.gz"; then + error "Failed to download binary" + error "The binary may not be available yet. Try Docker installation:" + echo " curl -fsSL https://raw.githubusercontent.com/$REPO/main/install.sh | bash -s -- --docker" + exit 1 + fi + + # Extract + tar -xzf "$tmp_dir/zerobuild.tar.gz" -C "$tmp_dir" + + # Install + mkdir -p "$INSTALL_DIR" + mv "$tmp_dir/zerobuild" "$INSTALL_DIR/zerobuild" + chmod +x "$INSTALL_DIR/zerobuild" + + success "ZeroBuild binary installed to $INSTALL_DIR/zerobuild" +} + +install_source() { + info "Building ZeroBuild from source..." + + if ! have_cmd cargo; then + error "Rust/Cargo is required to build from source." + error "Install Rust: https://rustup.rs/" + error "Or use Docker installation:" + echo " curl -fsSL https://raw.githubusercontent.com/$REPO/main/install.sh | bash -s -- --docker" + exit 1 + fi + + # Clone repo + local tmp_dir="$(mktemp -d)" + trap "rm -rf $tmp_dir" EXIT + + info "Cloning repository..." + git clone --depth 1 "https://github.com/$REPO.git" "$tmp_dir/zerobuild" + + info "Building (this may take a few minutes)..." + cd "$tmp_dir/zerobuild" + cargo build --release --locked + + # Install + mkdir -p "$INSTALL_DIR" + cp "$tmp_dir/zerobuild/target/release/zerobuild" "$INSTALL_DIR/zerobuild" + chmod +x "$INSTALL_DIR/zerobuild" + + success "ZeroBuild built and installed to $INSTALL_DIR/zerobuild" +} + +# Main installation logic +main() { + local method="${1:-auto}" + + # Parse arguments + case "$method" in + --docker|-d) + method="docker" + ;; + --binary|-b) + method="binary" + ;; + --source|-s) + method="source" + ;; + --help|-h) + cat <<'EOF' +ZeroBuild One-Click Installer + +Usage: + curl -fsSL https://raw.githubusercontent.com/PotLock/zerobuild/main/install.sh | bash + +Options: + --docker, -d Install using Docker (recommended, fastest) + --binary, -b Install pre-built binary + --source, -s Build and install from source + --help, -h Show this help message + +Environment: + INSTALL_DIR Installation directory (default: ~/.local/bin) + +Examples: + # Default: auto-detect best method + curl -fsSL ... | bash + + # Force Docker installation + curl -fsSL ... | bash -s -- --docker + + # Install to custom directory + INSTALL_DIR=/usr/local/bin curl -fsSL ... | bash +EOF + exit 0 + ;; + esac + + echo "" + echo " ╔══════════════════════════════════════════╗" + echo " ║ ZeroBuild Installer ║" + echo " ║ Autonomous Software Factory Agent ║" + echo " ╚══════════════════════════════════════════╝" + echo "" + + # Auto-detect method + if [[ "$method" == "auto" ]]; then + if have_cmd docker || have_cmd podman; then + method="docker" + info "Docker detected, using Docker installation method" + elif have_cmd cargo; then + method="source" + info "Cargo detected, building from source" + else + method="binary" + info "Attempting binary installation" + fi + fi + + # Run installation + case "$method" in + docker) + install_docker + ;; + binary) + install_binary + ;; + source) + install_source + ;; + *) + error "Unknown installation method: $method" + exit 1 + ;; + esac + + # Verify installation + if [[ -x "$INSTALL_DIR/zerobuild" ]]; then + echo "" + success "Installation complete!" + echo "" + info "Next steps:" + echo " 1. Run: export PATH=\"$INSTALL_DIR:\$PATH\" (if not in PATH)" + echo " 2. Setup: zerobuild onboard" + echo " 3. Usage: zerobuild --help" + echo "" + info "Documentation: https://github.com/$REPO" + info "Support: https://github.com/$REPO/issues" + fi +} + +main "$@" diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index 11399b8..ef69bca 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -186,7 +186,7 @@ install_prebuilt_binary() { return 1 fi - archive_url="https://github.com/zeroclaw-labs/zeroclaw/releases/latest/download/zerobuild-${target}.tar.gz" + archive_url="https://github.com/PotLock/zerobuild/releases/latest/download/zerobuild-${target}.tar.gz" temp_dir="$(mktemp -d -t zerobuild-prebuilt-XXXXXX)" archive_path="$temp_dir/zerobuild-${target}.tar.gz" @@ -721,7 +721,7 @@ MSG SCRIPT_PATH="${BASH_SOURCE[0]:-$0}" SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" >/dev/null 2>&1 && pwd || pwd)" ROOT_DIR="$(cd "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd || pwd)" -REPO_URL="https://github.com/zeroclaw-labs/zeroclaw.git" +REPO_URL="https://github.com/PotLock/zerobuild.git" ORIGINAL_ARG_COUNT=$# GUIDED_MODE="auto" diff --git a/zerobuild_install.sh b/zerobuild_install.sh index 5e67514..a2471f0 100755 --- a/zerobuild_install.sh +++ b/zerobuild_install.sh @@ -1,88 +1,47 @@ -#!/usr/bin/env sh -set -eu - -have_cmd() { - command -v "$1" >/dev/null 2>&1 +#!/usr/bin/env bash +# +# ZeroBuild Install Script +# +# This script provides a quick way to install ZeroBuild. +# It delegates to the main install.sh for consistency. +# +# Quick install (one-liner): +# curl -fsSL https://raw.githubusercontent.com/PotLock/zerobuild/main/install.sh | bash +# +# Or from local repo: +# ./zerobuild_install.sh + +set -euo pipefail + +info() { + echo "==> $*" } -run_privileged() { - if [ "$(id -u)" -eq 0 ]; then - "$@" - elif have_cmd sudo; then - sudo "$@" - else - echo "error: sudo is required to install missing dependencies." >&2 - exit 1 - fi -} - -is_container_runtime() { - if [ -f /.dockerenv ] || [ -f /run/.containerenv ]; then - return 0 - fi - - if [ -r /proc/1/cgroup ] && grep -Eq '(docker|containerd|kubepods|podman|lxc)' /proc/1/cgroup; then - return 0 - fi - - return 1 +error() { + echo "error: $*" >&2 } -run_pacman() { - if ! is_container_runtime; then - run_privileged pacman "$@" - return $? - fi - - PACMAN_CFG_TMP="$(mktemp /tmp/zerobuild-pacman.XXXXXX.conf)" - cp /etc/pacman.conf "$PACMAN_CFG_TMP" - if ! grep -Eq '^[[:space:]]*DisableSandboxSyscalls([[:space:]]|$)' "$PACMAN_CFG_TMP"; then - printf '\nDisableSandboxSyscalls\n' >> "$PACMAN_CFG_TMP" - fi - - if run_privileged pacman --config "$PACMAN_CFG_TMP" "$@"; then - PACMAN_RC=0 +# Check if running from repo or remotely +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [[ -f "$SCRIPT_DIR/install.sh" ]]; then + # Running from repo - use local install script + info "Running local install script..." + exec bash "$SCRIPT_DIR/install.sh" "$@" +elif [[ -f "$SCRIPT_DIR/scripts/bootstrap.sh" ]]; then + # Fallback to bootstrap for development + info "Running bootstrap script..." + exec bash "$SCRIPT_DIR/scripts/bootstrap.sh" "$@" +else + # Running remotely or standalone - download and run main install script + info "Downloading ZeroBuild installer..." + + if command -v curl >/dev/null 2>&1; then + exec bash -c "$(curl -fsSL https://raw.githubusercontent.com/PotLock/zerobuild/main/install.sh)" -- "$@" + elif command -v wget >/dev/null 2>&1; then + exec bash -c "$(wget -qO- https://raw.githubusercontent.com/PotLock/zerobuild/main/install.sh)" -- "$@" else - PACMAN_RC=$? - fi - rm -f "$PACMAN_CFG_TMP" - return "$PACMAN_RC" -} - -ensure_bash() { - if have_cmd bash; then - return 0 - fi - - echo "==> bash not found; attempting to install it" - if have_cmd apk; then - run_privileged apk add --no-cache bash - elif have_cmd apt-get; then - run_privileged apt-get update -qq - run_privileged apt-get install -y bash - elif have_cmd dnf; then - run_privileged dnf install -y bash - elif have_cmd pacman; then - run_pacman -Sy --noconfirm - run_pacman -S --noconfirm --needed bash - else - echo "error: unsupported package manager; install bash manually and retry." >&2 + error "curl or wget is required to download the installer" exit 1 fi -} - -ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" >/dev/null 2>&1 && pwd || pwd)" -BOOTSTRAP_SCRIPT="$ROOT_DIR/scripts/bootstrap.sh" - -if [ ! -f "$BOOTSTRAP_SCRIPT" ]; then - echo "error: scripts/bootstrap.sh not found from repository root." >&2 - exit 1 -fi - -ensure_bash - -if [ "$#" -eq 0 ]; then - exec bash "$BOOTSTRAP_SCRIPT" --guided fi - -exec bash "$BOOTSTRAP_SCRIPT" "$@"