Skip to content

Commit 5c6a6d6

Browse files
committed
setup cli cI
1 parent e31f898 commit 5c6a6d6

5 files changed

Lines changed: 274 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Set up Go
21+
uses: actions/setup-go@v5
22+
with:
23+
go-version-file: go.mod
24+
25+
- name: Run GoReleaser
26+
uses: goreleaser/goreleaser-action@v6
27+
with:
28+
distribution: goreleaser
29+
version: "~> v2"
30+
args: release --clean
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.goreleaser.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
version: 2
2+
3+
project_name: dune-cli
4+
5+
before:
6+
hooks:
7+
- go mod tidy
8+
9+
builds:
10+
- main: ./cmd
11+
binary: dune
12+
env:
13+
- CGO_ENABLED=0
14+
ldflags:
15+
- -s -w
16+
- -X main.version={{.Version}}
17+
- -X main.commit={{.Commit}}
18+
- -X main.date={{.Date}}
19+
goos:
20+
- linux
21+
- darwin
22+
- windows
23+
goarch:
24+
- amd64
25+
- arm64
26+
27+
archives:
28+
- format: tar.gz
29+
name_template: >-
30+
{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}
31+
format_overrides:
32+
- goos: windows
33+
format: zip
34+
35+
checksum:
36+
name_template: "checksums.txt"
37+
38+
changelog:
39+
sort: asc
40+
filters:
41+
exclude:
42+
- "^docs:"
43+
- "^test:"
44+
- "^ci:"
45+
- "^chore:"
46+
47+
release:
48+
github:
49+
owner: duneanalytics
50+
name: cli
51+
draft: false
52+
prerelease: auto
53+
extra_files:
54+
- glob: install.sh

cli/root.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ func init() {
4848
}
4949

5050
// Execute runs the root command via Fang.
51-
func Execute() {
51+
func Execute(version, commit, date string) {
52+
rootCmd.Version = fmt.Sprintf("%s (commit: %s, built: %s)", version, commit, date)
53+
5254
if err := fang.Execute(context.Background(), rootCmd); err != nil {
5355
fmt.Fprintln(os.Stderr, err)
5456
os.Exit(1)

cmd/main.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ package main
22

33
import "github.com/duneanalytics/cli/cli"
44

5+
// Set by GoReleaser via ldflags.
6+
var (
7+
version = "dev"
8+
commit = "none"
9+
date = "unknown"
10+
)
11+
512
func main() {
6-
cli.Execute()
13+
cli.Execute(version, commit, date)
714
}

install.sh

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#!/bin/sh
2+
# Dune CLI installer
3+
# Usage: curl -sSfL https://get.dune.com/cli | bash
4+
#
5+
# Environment variables:
6+
# INSTALL_DIR — installation directory (default: /usr/local/bin)
7+
# VERSION — specific version to install (default: latest)
8+
9+
set -e
10+
11+
REPO="duneanalytics/cli"
12+
BINARY="dune"
13+
PROJECT="dune-cli"
14+
15+
main() {
16+
need_cmd uname
17+
need_cmd mktemp
18+
need_cmd chmod
19+
need_cmd rm
20+
21+
os=$(detect_os)
22+
arch=$(detect_arch)
23+
version=$(resolve_version)
24+
25+
if [ -z "$version" ]; then
26+
err "could not determine latest version"
27+
fi
28+
29+
# Strip leading 'v' for archive name
30+
version_num="${version#v}"
31+
32+
install_dir="${INSTALL_DIR:-/usr/local/bin}"
33+
34+
case "$os" in
35+
windows) ext="zip" ;;
36+
*) ext="tar.gz" ;;
37+
esac
38+
39+
archive="${PROJECT}_${version_num}_${os}_${arch}.${ext}"
40+
url="https://github.com/${REPO}/releases/download/${version}/${archive}"
41+
checksum_url="https://github.com/${REPO}/releases/download/${version}/checksums.txt"
42+
43+
tmp=$(mktemp -d)
44+
trap 'rm -rf "$tmp"' EXIT
45+
46+
log "Downloading ${BINARY} ${version} for ${os}/${arch}..."
47+
download "$url" "$tmp/$archive"
48+
download "$checksum_url" "$tmp/checksums.txt"
49+
50+
log "Verifying checksum..."
51+
verify_checksum "$tmp/$archive" "$tmp/checksums.txt" "$archive"
52+
53+
log "Extracting..."
54+
case "$ext" in
55+
tar.gz) tar -xzf "$tmp/$archive" -C "$tmp" ;;
56+
zip) need_cmd unzip; unzip -q "$tmp/$archive" -d "$tmp" ;;
57+
esac
58+
59+
binary_name="$BINARY"
60+
if [ "$os" = "windows" ]; then
61+
binary_name="${BINARY}.exe"
62+
fi
63+
64+
if [ ! -f "$tmp/$binary_name" ]; then
65+
err "binary '$binary_name' not found in archive"
66+
fi
67+
68+
chmod +x "$tmp/$binary_name"
69+
70+
if [ -w "$install_dir" ]; then
71+
mv "$tmp/$binary_name" "$install_dir/$binary_name"
72+
else
73+
log "Installing to ${install_dir} (requires sudo)..."
74+
sudo mv "$tmp/$binary_name" "$install_dir/$binary_name"
75+
fi
76+
77+
log "Installed ${BINARY} ${version} to ${install_dir}/${binary_name}"
78+
}
79+
80+
detect_os() {
81+
os=$(uname -s | tr '[:upper:]' '[:lower:]')
82+
case "$os" in
83+
linux*) echo "linux" ;;
84+
darwin*) echo "darwin" ;;
85+
mingw*|msys*|cygwin*) echo "windows" ;;
86+
*) err "unsupported OS: $os" ;;
87+
esac
88+
}
89+
90+
detect_arch() {
91+
arch=$(uname -m)
92+
case "$arch" in
93+
x86_64|amd64) echo "amd64" ;;
94+
aarch64|arm64) echo "arm64" ;;
95+
*) err "unsupported architecture: $arch" ;;
96+
esac
97+
}
98+
99+
resolve_version() {
100+
if [ -n "$VERSION" ]; then
101+
case "$VERSION" in
102+
v*) echo "$VERSION" ;;
103+
*) echo "v$VERSION" ;;
104+
esac
105+
return
106+
fi
107+
108+
if has curl; then
109+
curl -sSfL -H "Accept: application/json" \
110+
"https://api.github.com/repos/${REPO}/releases/latest" \
111+
| sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p'
112+
elif has wget; then
113+
wget -qO- --header="Accept: application/json" \
114+
"https://api.github.com/repos/${REPO}/releases/latest" \
115+
| sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p'
116+
else
117+
err "need curl or wget to determine latest version"
118+
fi
119+
}
120+
121+
download() {
122+
url="$1"
123+
dest="$2"
124+
125+
if has curl; then
126+
curl -sSfL -o "$dest" "$url"
127+
elif has wget; then
128+
wget -qO "$dest" "$url"
129+
else
130+
err "need curl or wget to download files"
131+
fi
132+
}
133+
134+
verify_checksum() {
135+
file="$1"
136+
checksum_file="$2"
137+
archive_name="$3"
138+
139+
expected=$(awk -v name="$archive_name" '$2 == name || $2 == "*"name { print $1; exit }' "$checksum_file")
140+
if [ -z "$expected" ]; then
141+
err "checksum not found for $archive_name"
142+
fi
143+
144+
if has sha256sum; then
145+
actual=$(sha256sum "$file" | awk '{print $1}')
146+
elif has shasum; then
147+
actual=$(shasum -a 256 "$file" | awk '{print $1}')
148+
else
149+
log "WARNING: could not verify checksum (no sha256sum or shasum found)"
150+
return 0
151+
fi
152+
153+
if [ "$expected" != "$actual" ]; then
154+
err "checksum mismatch: expected $expected, got $actual"
155+
fi
156+
}
157+
158+
has() {
159+
command -v "$1" > /dev/null 2>&1
160+
}
161+
162+
need_cmd() {
163+
if ! has "$1"; then
164+
err "required command not found: $1"
165+
fi
166+
}
167+
168+
log() {
169+
echo " $*" >&2
170+
}
171+
172+
err() {
173+
log "error: $*"
174+
exit 1
175+
}
176+
177+
main "$@"

0 commit comments

Comments
 (0)