Skip to content

Commit a31c01b

Browse files
committed
feat: add release workflow and curl install scripts
1 parent 34027fd commit a31c01b

8 files changed

Lines changed: 409 additions & 5 deletions

File tree

.github/workflows/release.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Setup Go
20+
uses: actions/setup-go@v5
21+
with:
22+
go-version-file: go.mod
23+
cache: true
24+
25+
- name: Run tests
26+
run: go test ./...
27+
28+
- name: Build release archives
29+
run: bash ./scripts/build-release.sh "${GITHUB_REF_NAME}"
30+
31+
- name: Publish GitHub release
32+
uses: softprops/action-gh-release@v2
33+
with:
34+
files: |
35+
dist/*.tar.gz
36+
dist/checksums.txt
37+
generate_release_notes: true

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.runtime/
22
bin/
3+
dist/
34
wechat-codex
45
*.pid
56
service.log

README.md

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,62 @@
88
- **稳定消息轮询**:基于 iLink API 稳定接收并处理微信消息。
99
- **进程守护管理**:原生支持将轮询服务一键挂载至操作系统后台运行。
1010

11-
## 🛠 编译安装
11+
## 🚀 一键安装
1212

13-
确保你的环境中已安装 Go 1.16+。
13+
发布版本会在推送 `v*` tag 后自动构建并上传到 GitHub Releases,当前提供:
14+
15+
- macOS `amd64` / `arm64`
16+
- Linux `amd64` / `arm64`
17+
18+
直接安装最新版本:
19+
20+
```bash
21+
curl -fsSL https://raw.githubusercontent.com/Arlowen/wechat-codex/main/install.sh | bash
22+
```
23+
24+
安装指定版本:
25+
26+
```bash
27+
curl -fsSL https://raw.githubusercontent.com/Arlowen/wechat-codex/main/install.sh | WECHAT_CODEX_VERSION=v0.1.0 bash
28+
```
29+
30+
安装到自定义目录:
31+
32+
```bash
33+
curl -fsSL https://raw.githubusercontent.com/Arlowen/wechat-codex/main/install.sh | INSTALL_DIR="$HOME/.local/bin" bash
34+
```
35+
36+
安装完成后可执行:
1437

15-
**使用构建脚本(MacOS/Linux):**
38+
```bash
39+
wechat-codex version
40+
```
41+
42+
## 🧹 一键卸载
43+
44+
卸载已安装的二进制:
45+
46+
```bash
47+
curl -fsSL https://raw.githubusercontent.com/Arlowen/wechat-codex/main/uninstall.sh | bash
48+
```
49+
50+
如果是安装到了自定义目录:
51+
52+
```bash
53+
curl -fsSL https://raw.githubusercontent.com/Arlowen/wechat-codex/main/uninstall.sh | INSTALL_DIR="$HOME/.local/bin" bash
54+
```
55+
56+
如果还需要一并清理运行时数据 `~/.wechat-codex`
57+
58+
```bash
59+
curl -fsSL https://raw.githubusercontent.com/Arlowen/wechat-codex/main/uninstall.sh | WECHAT_CODEX_PURGE_DATA=1 bash
60+
```
61+
62+
## 🛠 本地编译
63+
64+
确保你的环境中已安装 Go 1.25+。
65+
66+
**使用构建脚本(macOS/Linux):**
1667
```bash
1768
./all_build.sh
1869
```
@@ -22,6 +73,11 @@
2273
go build -o bin/wechat-codex .
2374
```
2475

76+
**本地生成 release 包:**
77+
```bash
78+
./scripts/build-release.sh v0.1.0
79+
```
80+
2581
## 📖 使用指南
2682

2783
### 1. 启动服务与微信扫码登录

cmd/root.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,16 @@ import (
77
"github.com/spf13/cobra"
88
)
99

10+
var (
11+
Version = "dev"
12+
Commit = "unknown"
13+
BuildDate = "unknown"
14+
)
15+
1016
var rootCmd = &cobra.Command{
11-
Use: "wechat-codex",
12-
Short: "Go version of wechat-codex for WeChat bot operations",
17+
Use: "wechat-codex",
18+
Short: "Go version of wechat-codex for WeChat bot operations",
19+
Version: Version,
1320
CompletionOptions: cobra.CompletionOptions{
1421
DisableDefaultCmd: true,
1522
},

cmd/version.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package cmd
2+
3+
import (
4+
"wechat-codex/output"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var versionCmd = &cobra.Command{
10+
Use: "version",
11+
Short: "Print version information",
12+
Args: cobra.NoArgs,
13+
Run: func(cmd *cobra.Command, args []string) {
14+
output.Infof("version: %s", Version)
15+
if Commit != "" && Commit != "unknown" {
16+
output.Infof("commit: %s", Commit)
17+
}
18+
if BuildDate != "" && BuildDate != "unknown" {
19+
output.Infof("built at: %s", BuildDate)
20+
}
21+
},
22+
}
23+
24+
func init() {
25+
rootCmd.AddCommand(versionCmd)
26+
}

install.sh

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
REPO="${WECHAT_CODEX_REPO:-Arlowen/wechat-codex}"
6+
VERSION="${WECHAT_CODEX_VERSION:-latest}"
7+
BASE_URL="${WECHAT_CODEX_BASE_URL:-}"
8+
BIN_NAME="wechat-codex"
9+
INSTALL_DIR="${INSTALL_DIR:-}"
10+
TMP_DIR=""
11+
12+
log() {
13+
printf '[install] %s\n' "$*"
14+
}
15+
16+
fail() {
17+
printf '[install] ERROR: %s\n' "$*" >&2
18+
exit 1
19+
}
20+
21+
cleanup() {
22+
if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then
23+
rm -rf "$TMP_DIR"
24+
fi
25+
}
26+
27+
need_cmd() {
28+
command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
29+
}
30+
31+
detect_os() {
32+
case "$(uname -s)" in
33+
Linux) printf 'linux\n' ;;
34+
Darwin) printf 'darwin\n' ;;
35+
*) fail "unsupported operating system: $(uname -s)" ;;
36+
esac
37+
}
38+
39+
detect_arch() {
40+
case "$(uname -m)" in
41+
x86_64|amd64) printf 'amd64\n' ;;
42+
arm64|aarch64) printf 'arm64\n' ;;
43+
*) fail "unsupported architecture: $(uname -m)" ;;
44+
esac
45+
}
46+
47+
choose_install_dir() {
48+
if [ -n "$INSTALL_DIR" ]; then
49+
mkdir -p "$INSTALL_DIR"
50+
printf '%s\n' "$INSTALL_DIR"
51+
return
52+
fi
53+
54+
if [ -d "/usr/local/bin" ] && [ -w "/usr/local/bin" ]; then
55+
printf '/usr/local/bin\n'
56+
return
57+
fi
58+
59+
if mkdir -p "$HOME/.local/bin" 2>/dev/null; then
60+
printf '%s\n' "$HOME/.local/bin"
61+
return
62+
fi
63+
64+
fail "no writable install directory found, please set INSTALL_DIR=/path/to/bin"
65+
}
66+
67+
download_base_url() {
68+
if [ -n "$BASE_URL" ]; then
69+
printf '%s\n' "$BASE_URL"
70+
return
71+
fi
72+
73+
if [ "$VERSION" = "latest" ]; then
74+
printf 'https://github.com/%s/releases/latest/download\n' "$REPO"
75+
else
76+
printf 'https://github.com/%s/releases/download/%s\n' "$REPO" "$VERSION"
77+
fi
78+
}
79+
80+
verify_checksum() {
81+
local asset="$1"
82+
local checksum_url="$2"
83+
local checksum_file="$TMP_DIR/checksums.txt"
84+
local checksum_line="$TMP_DIR/checksum.line"
85+
86+
if ! command -v sha256sum >/dev/null 2>&1 && ! command -v shasum >/dev/null 2>&1; then
87+
log "sha256 tool not found, skip checksum verification"
88+
return
89+
fi
90+
91+
if ! curl -fsSL "$checksum_url" -o "$checksum_file"; then
92+
log "checksums.txt not found, skip checksum verification"
93+
return
94+
fi
95+
96+
if ! grep "[[:space:]]$asset\$" "$checksum_file" >"$checksum_line"; then
97+
log "checksum for $asset not found, skip checksum verification"
98+
return
99+
fi
100+
101+
if command -v sha256sum >/dev/null 2>&1; then
102+
(cd "$TMP_DIR" && sha256sum -c "$(basename "$checksum_line")")
103+
else
104+
(cd "$TMP_DIR" && shasum -a 256 -c "$(basename "$checksum_line")")
105+
fi
106+
}
107+
108+
main() {
109+
local os arch install_dir asset base_url archive_url checksum_url archive_path binary_path
110+
111+
trap cleanup EXIT
112+
113+
need_cmd curl
114+
need_cmd tar
115+
need_cmd mktemp
116+
need_cmd uname
117+
118+
os="$(detect_os)"
119+
arch="$(detect_arch)"
120+
install_dir="$(choose_install_dir)"
121+
asset="${BIN_NAME}_${os}_${arch}.tar.gz"
122+
base_url="$(download_base_url)"
123+
archive_url="${base_url}/${asset}"
124+
checksum_url="${base_url}/checksums.txt"
125+
126+
TMP_DIR="$(mktemp -d)"
127+
archive_path="$TMP_DIR/$asset"
128+
129+
log "downloading ${archive_url}"
130+
curl -fsSL "$archive_url" -o "$archive_path"
131+
132+
verify_checksum "$asset" "$checksum_url"
133+
134+
tar -xzf "$archive_path" -C "$TMP_DIR"
135+
binary_path="$(find "$TMP_DIR" -type f -name "$BIN_NAME" | head -n 1)"
136+
[ -n "$binary_path" ] || fail "binary not found in release archive"
137+
138+
cp "$binary_path" "$install_dir/$BIN_NAME"
139+
chmod 0755 "$install_dir/$BIN_NAME"
140+
141+
log "installed to $install_dir/$BIN_NAME"
142+
if ! printf ':%s:' "$PATH" | grep -q ":$install_dir:"; then
143+
log "$install_dir is not in PATH"
144+
log "add this line to your shell profile: export PATH=\"$install_dir:\$PATH\""
145+
fi
146+
log "verify with: $BIN_NAME version"
147+
}
148+
149+
main "$@"

scripts/build-release.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6+
DIST_DIR="${DIST_DIR:-$ROOT_DIR/dist}"
7+
VERSION="${1:-${GITHUB_REF_NAME:-dev}}"
8+
COMMIT_SHA="${COMMIT_SHA:-$(git -C "$ROOT_DIR" rev-parse --short HEAD 2>/dev/null || printf 'unknown')}"
9+
BUILD_DATE="${BUILD_DATE:-$(date -u '+%Y-%m-%dT%H:%M:%SZ')}"
10+
TARGETS=(
11+
"darwin amd64"
12+
"darwin arm64"
13+
"linux amd64"
14+
"linux arm64"
15+
)
16+
17+
cd "$ROOT_DIR"
18+
rm -rf "$DIST_DIR"
19+
mkdir -p "$DIST_DIR"
20+
21+
for target in "${TARGETS[@]}"; do
22+
read -r goos goarch <<<"$target"
23+
package_name="wechat-codex_${goos}_${goarch}"
24+
stage_dir="$DIST_DIR/$package_name"
25+
26+
printf '==> building %s\n' "$package_name"
27+
mkdir -p "$stage_dir"
28+
29+
CGO_ENABLED=0 GOOS="$goos" GOARCH="$goarch" \
30+
go build -trimpath \
31+
-ldflags="-s -w -X wechat-codex/cmd.Version=$VERSION -X wechat-codex/cmd.Commit=$COMMIT_SHA -X wechat-codex/cmd.BuildDate=$BUILD_DATE" \
32+
-o "$stage_dir/wechat-codex" .
33+
34+
cp README.md "$stage_dir/README.md"
35+
cp docs/manual.md "$stage_dir/manual.md"
36+
cp install.sh "$stage_dir/install.sh"
37+
cp uninstall.sh "$stage_dir/uninstall.sh"
38+
chmod 0755 "$stage_dir/wechat-codex" "$stage_dir/install.sh" "$stage_dir/uninstall.sh"
39+
40+
tar -C "$DIST_DIR" -czf "$DIST_DIR/$package_name.tar.gz" "$package_name"
41+
rm -rf "$stage_dir"
42+
done
43+
44+
(
45+
cd "$DIST_DIR"
46+
: > checksums.txt
47+
for file in *.tar.gz; do
48+
if command -v sha256sum >/dev/null 2>&1; then
49+
sha256sum "$file" >> checksums.txt
50+
else
51+
shasum -a 256 "$file" >> checksums.txt
52+
fi
53+
done
54+
)
55+
56+
printf 'release artifacts written to %s\n' "$DIST_DIR"

0 commit comments

Comments
 (0)