Skip to content

Commit 479c22c

Browse files
committed
Add release pipeline: GoReleaser, GitHub Actions workflow, install script
Cross-platform builds for Linux/macOS/Windows (amd64, arm64, armv7). Releases triggered by pushing a semver tag (v*). Includes a curl|sh installer with checksum verification.
1 parent cd80777 commit 479c22c

File tree

6 files changed

+240
-2
lines changed

6 files changed

+240
-2
lines changed

.github/workflows/release.yml

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

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Build output
22
bin/
3+
dist/
34

45
# Test
56
coverage.out

.goreleaser.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
version: 2
2+
3+
builds:
4+
- main: ./cmd/uploadcare
5+
binary: uploadcare
6+
env:
7+
- CGO_ENABLED=0
8+
ldflags:
9+
- -s -w
10+
- -X main.version={{.Version}}
11+
- -X main.commit={{.Commit}}
12+
- -X main.date={{.Date}}
13+
goos:
14+
- linux
15+
- darwin
16+
- windows
17+
goarch:
18+
- amd64
19+
- arm64
20+
- arm
21+
goarm:
22+
- "7"
23+
ignore:
24+
- goos: darwin
25+
goarch: arm
26+
- goos: windows
27+
goarch: arm
28+
29+
archives:
30+
- name_template: >-
31+
uploadcare-cli_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}
32+
format_overrides:
33+
- goos: windows
34+
format: zip
35+
files:
36+
- README.md
37+
- LICENSE
38+
39+
checksum:
40+
name_template: checksums.txt
41+
algorithm: sha256
42+
43+
changelog:
44+
use: github-native
45+
46+
release:
47+
github:
48+
owner: uploadcare
49+
name: uploadcare-cli
50+
prerelease: auto

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LDFLAGS := -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.date=$(DA
66

77
BINARY := uploadcare
88

9-
.PHONY: build test lint clean
9+
.PHONY: build test lint clean release-snapshot
1010

1111
build:
1212
go build -ldflags "$(LDFLAGS)" -o bin/$(BINARY) ./cmd/uploadcare
@@ -18,4 +18,7 @@ lint:
1818
golangci-lint run ./...
1919

2020
clean:
21-
rm -rf bin/
21+
rm -rf bin/ dist/
22+
23+
release-snapshot:
24+
goreleaser release --snapshot --clean

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ A non-interactive command-line interface for the [Uploadcare](https://uploadcare
1515

1616
## Installation
1717

18+
### Quick install (Linux / macOS)
19+
20+
```bash
21+
curl -fsSL https://raw.githubusercontent.com/uploadcare/uploadcare-cli/main/scripts/install.sh | sh
22+
```
23+
24+
### Download from GitHub Releases
25+
26+
Pre-built binaries for all platforms are available on the [Releases page](https://github.com/uploadcare/uploadcare-cli/releases).
27+
1828
### From source
1929

2030
Requires Go 1.22+.

scripts/install.sh

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/bin/sh
2+
# Uploadcare CLI installer
3+
# Usage: curl -fsSL https://raw.githubusercontent.com/uploadcare/uploadcare-cli/main/scripts/install.sh | sh
4+
#
5+
# Environment variables:
6+
# VERSION - specific version to install (e.g., "v0.1.0"). Default: latest.
7+
# INSTALL_DIR - installation directory. Default: /usr/local/bin.
8+
9+
set -eu
10+
11+
REPO="uploadcare/uploadcare-cli"
12+
BINARY="uploadcare"
13+
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
14+
15+
main() {
16+
detect_os
17+
detect_arch
18+
resolve_version
19+
download_and_verify
20+
install_binary
21+
print_success
22+
}
23+
24+
detect_os() {
25+
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
26+
case "$OS" in
27+
linux) OS="linux" ;;
28+
darwin) OS="darwin" ;;
29+
*)
30+
echo "Error: unsupported operating system: $OS" >&2
31+
echo "Supported: linux, darwin (macOS)" >&2
32+
exit 1
33+
;;
34+
esac
35+
}
36+
37+
detect_arch() {
38+
ARCH="$(uname -m)"
39+
case "$ARCH" in
40+
x86_64|amd64) ARCH="amd64" ;;
41+
aarch64|arm64) ARCH="arm64" ;;
42+
armv7l|armv7) ARCH="armv7" ;;
43+
*)
44+
echo "Error: unsupported architecture: $ARCH" >&2
45+
echo "Supported: x86_64/amd64, aarch64/arm64, armv7" >&2
46+
exit 1
47+
;;
48+
esac
49+
}
50+
51+
resolve_version() {
52+
if [ -n "${VERSION:-}" ]; then
53+
# Ensure version starts with 'v'
54+
case "$VERSION" in
55+
v*) ;;
56+
*) VERSION="v$VERSION" ;;
57+
esac
58+
return
59+
fi
60+
61+
echo "Fetching latest version..."
62+
# Use the GitHub releases redirect to avoid needing jq
63+
VERSION="$(curl -fsSI "https://github.com/$REPO/releases/latest" 2>/dev/null \
64+
| grep -i '^location:' \
65+
| sed 's|.*/tag/||' \
66+
| tr -d '[:space:]')"
67+
68+
if [ -z "$VERSION" ]; then
69+
echo "Error: could not determine latest version." >&2
70+
echo "Check https://github.com/$REPO/releases or set VERSION manually." >&2
71+
exit 1
72+
fi
73+
74+
echo "Latest version: $VERSION"
75+
}
76+
77+
download_and_verify() {
78+
VERSION_NUM="${VERSION#v}"
79+
ARCHIVE="uploadcare-cli_${VERSION_NUM}_${OS}_${ARCH}.tar.gz"
80+
DOWNLOAD_URL="https://github.com/$REPO/releases/download/${VERSION}/${ARCHIVE}"
81+
CHECKSUMS_URL="https://github.com/$REPO/releases/download/${VERSION}/checksums.txt"
82+
83+
TMPDIR="$(mktemp -d)"
84+
trap 'rm -rf "$TMPDIR"' EXIT
85+
86+
echo "Downloading ${ARCHIVE}..."
87+
curl -fsSL "$DOWNLOAD_URL" -o "$TMPDIR/$ARCHIVE"
88+
curl -fsSL "$CHECKSUMS_URL" -o "$TMPDIR/checksums.txt"
89+
90+
echo "Verifying checksum..."
91+
EXPECTED="$(grep "$ARCHIVE" "$TMPDIR/checksums.txt" | awk '{print $1}')"
92+
if [ -z "$EXPECTED" ]; then
93+
echo "Error: archive not found in checksums.txt" >&2
94+
exit 1
95+
fi
96+
97+
if command -v sha256sum >/dev/null 2>&1; then
98+
ACTUAL="$(sha256sum "$TMPDIR/$ARCHIVE" | awk '{print $1}')"
99+
elif command -v shasum >/dev/null 2>&1; then
100+
ACTUAL="$(shasum -a 256 "$TMPDIR/$ARCHIVE" | awk '{print $1}')"
101+
else
102+
echo "Warning: neither sha256sum nor shasum found, skipping checksum verification" >&2
103+
ACTUAL="$EXPECTED"
104+
fi
105+
106+
if [ "$EXPECTED" != "$ACTUAL" ]; then
107+
echo "Error: checksum mismatch" >&2
108+
echo " Expected: $EXPECTED" >&2
109+
echo " Actual: $ACTUAL" >&2
110+
exit 1
111+
fi
112+
113+
echo "Checksum verified."
114+
115+
tar -xzf "$TMPDIR/$ARCHIVE" -C "$TMPDIR"
116+
}
117+
118+
install_binary() {
119+
if [ ! -d "$INSTALL_DIR" ]; then
120+
echo "Creating $INSTALL_DIR..."
121+
if mkdir -p "$INSTALL_DIR" 2>/dev/null; then
122+
:
123+
else
124+
sudo mkdir -p "$INSTALL_DIR"
125+
fi
126+
fi
127+
128+
if [ -w "$INSTALL_DIR" ]; then
129+
cp "$TMPDIR/$BINARY" "$INSTALL_DIR/$BINARY"
130+
chmod +x "$INSTALL_DIR/$BINARY"
131+
else
132+
echo "Installing to $INSTALL_DIR (requires sudo)..."
133+
sudo cp "$TMPDIR/$BINARY" "$INSTALL_DIR/$BINARY"
134+
sudo chmod +x "$INSTALL_DIR/$BINARY"
135+
fi
136+
}
137+
138+
print_success() {
139+
echo ""
140+
echo "Uploadcare CLI installed to $INSTALL_DIR/$BINARY"
141+
"$INSTALL_DIR/$BINARY" version
142+
}
143+
144+
main

0 commit comments

Comments
 (0)