Skip to content

Commit 4aa8779

Browse files
committed
ci: add release automation and easy installation
1 parent 77ba2c2 commit 4aa8779

File tree

10 files changed

+352
-6
lines changed

10 files changed

+352
-6
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Build Release
2+
3+
on:
4+
release:
5+
types: [created]
6+
7+
permissions:
8+
contents: write
9+
10+
jobs:
11+
build:
12+
strategy:
13+
matrix:
14+
include:
15+
- target: x86_64-unknown-linux-gnu
16+
os: ubuntu-latest
17+
name: nanocode-linux-x86_64
18+
- target: aarch64-unknown-linux-gnu
19+
os: ubuntu-latest
20+
name: nanocode-linux-aarch64
21+
- target: aarch64-apple-darwin
22+
os: macos-latest
23+
name: nanocode-darwin-aarch64
24+
25+
runs-on: ${{ matrix.os }}
26+
steps:
27+
- uses: actions/checkout@v4
28+
29+
- name: Install Rust
30+
uses: dtolnay/rust-toolchain@stable
31+
with:
32+
targets: ${{ matrix.target }}
33+
34+
- name: Install dependencies (Linux)
35+
if: runner.os == 'Linux'
36+
run: |
37+
sudo apt-get update
38+
sudo apt-get install -y libssl-dev pkg-config
39+
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
40+
sudo apt-get install -y gcc-aarch64-linux-gnu
41+
fi
42+
43+
- name: Build
44+
run: |
45+
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
46+
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
47+
fi
48+
cargo build --release --target ${{ matrix.target }}
49+
50+
- name: Package
51+
run: |
52+
cd target/${{ matrix.target }}/release
53+
tar -czvf ../../../${{ matrix.name }}.tar.gz nanocode
54+
cd ../../..
55+
56+
- name: Upload Release Asset
57+
uses: softprops/action-gh-release@v1
58+
with:
59+
files: ${{ matrix.name }}.tar.gz

.github/workflows/ci.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
check:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Install Rust
19+
uses: dtolnay/rust-toolchain@stable
20+
with:
21+
components: rustfmt, clippy
22+
23+
- name: Cache cargo
24+
uses: actions/cache@v4
25+
with:
26+
path: |
27+
~/.cargo/bin/
28+
~/.cargo/registry/index/
29+
~/.cargo/registry/cache/
30+
~/.cargo/git/db/
31+
target/
32+
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
33+
34+
- name: Check formatting
35+
run: cargo fmt -- --check
36+
37+
- name: Clippy
38+
run: cargo clippy -- -D warnings
39+
40+
- name: Build
41+
run: cargo build --verbose
42+
43+
- name: Run tests
44+
run: cargo test --verbose

.github/workflows/commitlint.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: Commitlint
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened, edited]
6+
7+
jobs:
8+
commitlint:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
with:
13+
fetch-depth: 0
14+
15+
- name: Setup Node.js
16+
uses: actions/setup-node@v4
17+
with:
18+
node-version: '20'
19+
20+
- name: Install commitlint
21+
run: npm install --save-dev @commitlint/cli @commitlint/config-conventional
22+
23+
- name: Validate PR title
24+
env:
25+
PR_TITLE: ${{ github.event.pull_request.title }}
26+
run: echo "$PR_TITLE" | npx commitlint
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Release Please
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
jobs:
13+
release-please:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: googleapis/release-please-action@v4
17+
with:
18+
release-type: rust

.release-please-manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
".": "0.1.0"
3+
}

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
name = "nanocode"
33
version = "0.1.0"
44
edition = "2021"
5+
description = "A minimal AI-powered coding CLI assistant"
6+
license = "MIT"
7+
repository = "https://github.com/HybridAIOne/nano"
58

69
[dependencies]
710
colored = "2.1.0"
@@ -10,3 +13,4 @@ serde = { version = "1.0", features = ["derive"] }
1013
serde_json = "1.0"
1114
glob = "0.3"
1215
regex = "1.10"
16+
openssl = { version = "0.10", features = ["vendored"] }

README.md

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,39 @@ A minimal AI-powered coding CLI assistant written in Rust. Nanocode lets you int
1616
- **Color-Coded Output** - Easy-to-read terminal interface
1717
- **Safety Guards** - Limits tool iterations to prevent runaway executions
1818

19+
## Supported Platforms
20+
21+
- Linux x86_64
22+
- Linux aarch64
23+
- macOS aarch64 (Apple Silicon)
24+
25+
Intel Mac users: the installer will build from source automatically.
26+
1927
## Prerequisites
2028

21-
- Rust and Cargo (install from [rustup.rs](https://rustup.rs))
2229
- An OpenRouter API key or a HybridAI API key (HybridAI takes precedence if both are set)
2330

2431
## Installation
2532

26-
1. Clone this repository:
33+
### Quick Install (Linux/macOS)
34+
35+
```bash
36+
curl -fsSL https://raw.githubusercontent.com/HybridAIOne/nano/main/install.sh | bash
37+
```
38+
39+
This downloads a pre-built binary or builds from source if needed. Installs to `~/.local/bin/` by default.
40+
41+
### Using Cargo
42+
2743
```bash
28-
git clone <repository-url>
29-
cd nanocode
44+
cargo install --git https://github.com/HybridAIOne/nano
3045
```
3146

32-
2. Build the project:
47+
### From Source
48+
3349
```bash
34-
cargo build --release
50+
git clone https://github.com/HybridAIOne/nano && cd nano
51+
cargo install --path .
3552
```
3653

3754
## Configuration

commitlint.config.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module.exports = {
2+
extends: ['@commitlint/config-conventional'],
3+
rules: {
4+
'type-enum': [
5+
2,
6+
'always',
7+
[
8+
'feat',
9+
'fix',
10+
'docs',
11+
'style',
12+
'refactor',
13+
'perf',
14+
'test',
15+
'build',
16+
'ci',
17+
'chore',
18+
'revert',
19+
],
20+
],
21+
'subject-case': [2, 'always', 'lower-case'],
22+
'header-max-length': [2, 'always', 100],
23+
},
24+
};

install.sh

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Nanocode Installer
5+
# Usage: curl -fsSL https://raw.githubusercontent.com/HybridAIOne/nano/main/install.sh | bash
6+
7+
REPO="HybridAIOne/nano"
8+
BINARY_NAME="nanocode"
9+
INSTALL_DIR="${NANOCODE_INSTALL_DIR:-$HOME/.local/bin}"
10+
11+
# Colors
12+
RED='\033[0;31m'
13+
GREEN='\033[0;32m'
14+
YELLOW='\033[1;33m'
15+
NC='\033[0m' # No Color
16+
17+
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
18+
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
19+
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
20+
21+
# Detect OS and architecture
22+
detect_platform() {
23+
local os arch
24+
25+
case "$(uname -s)" in
26+
Linux*) os="linux" ;;
27+
Darwin*) os="darwin" ;;
28+
*) error "Unsupported OS: $(uname -s)" ;;
29+
esac
30+
31+
case "$(uname -m)" in
32+
x86_64|amd64) arch="x86_64" ;;
33+
aarch64|arm64) arch="aarch64" ;;
34+
*) error "Unsupported architecture: $(uname -m)" ;;
35+
esac
36+
37+
echo "${os}-${arch}"
38+
}
39+
40+
# Get latest release version
41+
get_latest_version() {
42+
curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | \
43+
grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/'
44+
}
45+
46+
# Download and install binary
47+
install_binary() {
48+
local version="$1"
49+
local platform="$2"
50+
local asset_name="${BINARY_NAME}-${platform}.tar.gz"
51+
local download_url="https://github.com/${REPO}/releases/download/${version}/${asset_name}"
52+
53+
info "Downloading ${BINARY_NAME} ${version} for ${platform}..."
54+
55+
local tmp_dir=$(mktemp -d)
56+
trap "rm -rf $tmp_dir" EXIT
57+
58+
if ! curl -fsSL "$download_url" -o "$tmp_dir/${BINARY_NAME}.tar.gz" 2>/dev/null; then
59+
return 1
60+
fi
61+
62+
tar -xzf "$tmp_dir/${BINARY_NAME}.tar.gz" -C "$tmp_dir"
63+
64+
mkdir -p "$INSTALL_DIR"
65+
mv "$tmp_dir/${BINARY_NAME}" "$INSTALL_DIR/${BINARY_NAME}"
66+
chmod +x "$INSTALL_DIR/${BINARY_NAME}"
67+
68+
return 0
69+
}
70+
71+
# Build from source
72+
build_from_source() {
73+
info "Building from source..."
74+
75+
if ! command -v cargo &>/dev/null; then
76+
error "Rust/Cargo not found. Install from https://rustup.rs"
77+
fi
78+
79+
local tmp_dir=$(mktemp -d)
80+
trap "rm -rf $tmp_dir" EXIT
81+
82+
git clone --depth 1 "https://github.com/${REPO}.git" "$tmp_dir/${BINARY_NAME}"
83+
cd "$tmp_dir/${BINARY_NAME}"
84+
85+
cargo build --release
86+
87+
mkdir -p "$INSTALL_DIR"
88+
mv target/release/${BINARY_NAME} "$INSTALL_DIR/${BINARY_NAME}"
89+
chmod +x "$INSTALL_DIR/${BINARY_NAME}"
90+
}
91+
92+
# Check if install dir is in PATH
93+
check_path() {
94+
if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
95+
warn "Add $INSTALL_DIR to your PATH:"
96+
echo ""
97+
echo " export PATH=\"\$PATH:$INSTALL_DIR\""
98+
echo ""
99+
echo "Add this line to your ~/.bashrc, ~/.zshrc, or shell config."
100+
fi
101+
}
102+
103+
main() {
104+
info "Installing ${BINARY_NAME}..."
105+
106+
local platform=$(detect_platform)
107+
info "Detected platform: $platform"
108+
109+
local version=$(get_latest_version)
110+
111+
if [ -n "$version" ]; then
112+
info "Latest version: $version"
113+
114+
if install_binary "$version" "$platform"; then
115+
info "Successfully installed ${BINARY_NAME} to $INSTALL_DIR/${BINARY_NAME}"
116+
else
117+
warn "Pre-built binary not available for $platform"
118+
build_from_source
119+
info "Successfully built and installed ${BINARY_NAME} to $INSTALL_DIR/${BINARY_NAME}"
120+
fi
121+
else
122+
warn "Could not determine latest version, building from source"
123+
build_from_source
124+
info "Successfully built and installed ${BINARY_NAME} to $INSTALL_DIR/${BINARY_NAME}"
125+
fi
126+
127+
check_path
128+
129+
echo ""
130+
info "Installation complete!"
131+
echo ""
132+
echo "Don't forget to set your API key:"
133+
echo " export OPENROUTER_API_KEY=\"your-api-key\""
134+
echo " # or"
135+
echo " export HYBRIDAI_API_KEY=\"your-api-key\""
136+
echo ""
137+
echo "Then run: ${BINARY_NAME}"
138+
echo ""
139+
}
140+
141+
main "$@"

release-please-config.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
3+
"packages": {
4+
".": {
5+
"release-type": "rust",
6+
"bump-minor-pre-major": false,
7+
"bump-patch-for-minor-pre-major": true
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)