Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,100 @@ jobs:
name: binaries
path: dist/*
retention-days: 30

homebrew:
name: Update Homebrew tap
runs-on: ubuntu-latest
needs: build
if: startsWith(github.ref, 'refs/tags/')
env:
# Set HOMEBREW_TAP_TOKEN (a fine-grained PAT with push access to the tap
# repo) to enable this job. Without it the job no-ops, so releases from
# forks or before the secret is configured never fail. HOMEBREW_TAP_REPO
# is the `homebrew-<tap>` repository backing `brew install <owner>/tap/sshx`.
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
HOMEBREW_TAP_REPO: talkincode/homebrew-tap
steps:
- name: Download release artifacts
if: ${{ env.HOMEBREW_TAP_TOKEN != '' }}
uses: actions/download-artifact@v4
with:
name: binaries
path: dist-artifacts

- name: Render and push formula
if: ${{ env.HOMEBREW_TAP_TOKEN != '' }}
run: |
set -euo pipefail
TAG="${GITHUB_REF#refs/tags/}" # e.g. v1.2.0
VERSION="${TAG#v}" # e.g. 1.2.0
BASE_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${TAG}"
CHECKSUMS="dist-artifacts/checksums.txt"

# Look up the sha256 for a given archive name from checksums.txt
# (format: "<sha256> <filename>", as produced by `sha256sum *`).
sha() {
local hash
hash="$(awk -v f="$1" '$2 == f { print $1; exit }' "$CHECKSUMS")"
[ -n "$hash" ] || { echo "missing checksum for $1" >&2; exit 1; }
echo "$hash"
}

DARWIN_ARM64_SHA="$(sha sshx-darwin-arm64.tar.gz)"
DARWIN_AMD64_SHA="$(sha sshx-darwin-amd64.tar.gz)"
LINUX_ARM64_SHA="$(sha sshx-linux-arm64.tar.gz)"
LINUX_AMD64_SHA="$(sha sshx-linux-amd64.tar.gz)"

git clone --depth 1 \
"https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/${HOMEBREW_TAP_REPO}.git" tap
mkdir -p tap/Formula

cat > tap/Formula/sshx.rb <<EOF
class Sshx < Formula
desc "Barrier-free SSH/SFTP CLI with a built-in OS-keyring password manager"
homepage "https://github.com/talkincode/sshx"
version "${VERSION}"
license "MIT"

on_macos do
if Hardware::CPU.arm?
url "${BASE_URL}/sshx-darwin-arm64.tar.gz"
sha256 "${DARWIN_ARM64_SHA}"
else
url "${BASE_URL}/sshx-darwin-amd64.tar.gz"
sha256 "${DARWIN_AMD64_SHA}"
end
end

on_linux do
if Hardware::CPU.arm?
url "${BASE_URL}/sshx-linux-arm64.tar.gz"
sha256 "${LINUX_ARM64_SHA}"
else
url "${BASE_URL}/sshx-linux-amd64.tar.gz"
sha256 "${LINUX_AMD64_SHA}"
end
end

def install
# Each archive contains a single, platform-suffixed binary
# (e.g. sshx-darwin-arm64); rename it to the plain "sshx" command.
bin.install Dir["sshx-*"].first => "sshx"
end

test do
assert_match version.to_s, shell_output("#{bin}/sshx --version")
end
end
EOF

cd tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/sshx.rb
if git diff --cached --quiet; then
echo "Formula already up to date for ${VERSION}"
else
git commit -m "sshx ${VERSION}"
git push
fi
3 changes: 2 additions & 1 deletion AGENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ unless the mission in §1–§3 is formally revised.
`scripts/release-note.sh` (`make renote`).
- `release.yml` cross-compiles and publishes artifacts on tag push.
- Install paths: `go install`, `install.sh` (Linux/macOS), `install.ps1`
(Windows), or manual binary download.
(Windows), a Homebrew tap (`talkincode/homebrew-tap`, opt-in via the
`HOMEBREW_TAP_TOKEN` secret), or manual binary download.

## 12. Guidelines for AI Coding Agents

Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- An mdBook documentation site with English and Chinese guides for getting
started, host management, SFTP, scripting, security, scenarios, and
troubleshooting.
- Release automation now publishes/updates a Homebrew tap formula
(`talkincode/homebrew-tap`) on every tagged release, so macOS/Linux users can
`brew install talkincode/tap/sshx`. The step is opt-in via the
`HOMEBREW_TAP_TOKEN` repository secret and no-ops otherwise.

### Changed

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ sshx -h=192.168.1.100 "uptime"

**Note:** Make sure `$GOPATH/bin` (typically `~/go/bin`) is in your PATH.

### Homebrew (macOS / Linux)

```bash
brew install talkincode/tap/sshx
```

This pulls prebuilt binaries from the [talkincode/homebrew-tap](https://github.com/talkincode/homebrew-tap) repository, updated automatically on every tagged release.

### One-Line Installation Script

#### Linux / macOS
Expand Down
8 changes: 8 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ sshx -h=192.168.1.100 "uptime"

**注意:** 确保 `$GOPATH/bin`(通常是 `~/go/bin`)在您的 PATH 中。

### Homebrew(macOS / Linux)

```bash
brew install talkincode/tap/sshx
```

该命令会从 [talkincode/homebrew-tap](https://github.com/talkincode/homebrew-tap) 仓库拉取预编译二进制文件,每次打 tag 发布时自动更新。

### 一键安装脚本

#### Linux / macOS
Expand Down
43 changes: 43 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ After pushing the tag, GitHub Actions will automatically:

5. ✅ Upload all binaries to the Release

6. ✅ Publish/update the Homebrew tap formula (if `HOMEBREW_TAP_TOKEN` is configured; see below)

### 5. Verify Release

Visit the GitHub Releases page to verify:
Expand Down Expand Up @@ -159,6 +161,47 @@ ls -lh bin/
2. Verify network connection
3. Review detailed error messages in Actions logs

## Homebrew Tap Publishing

On every tag push, the `homebrew` job in `.github/workflows/release.yml` renders and
pushes a `Formula/sshx.rb` file to the `talkincode/homebrew-tap` repository, so
users can run:

```bash
brew install talkincode/tap/sshx
```

The formula is built from the `checksums.txt` produced by the `build` job, and
covers `darwin`/`linux` on both `amd64` and `arm64`. Windows has no Homebrew
equivalent, so it is intentionally excluded from the formula.

### One-time setup

1. Create (or reuse) a `talkincode/homebrew-tap` repository with a `Formula/`
directory.
2. Generate a fine-grained GitHub Personal Access Token scoped to `Contents:
write` on that repository only.
3. Add it as a repository secret named `HOMEBREW_TAP_TOKEN` in `talkincode/sshx`
(Settings → Secrets and variables → Actions).

If `HOMEBREW_TAP_TOKEN` is not set, the `homebrew` job no-ops (its steps are
skipped) and the rest of the release is unaffected — this mirrors how the
project treats other optional publish integrations.

### Verifying a published formula

```bash
brew tap talkincode/tap
brew install sshx
sshx --version
```

Or inspect the rendered formula directly:

```
https://github.com/talkincode/homebrew-tap/blob/main/Formula/sshx.rb
```

## CI/CD Workflows

### Release Workflow (.github/workflows/release.yml)
Expand Down
2 changes: 1 addition & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ internal/sshclient

- 构建、发布和质量守护

Makefile 提供构建、测试、覆盖率、lint、跨平台编译和安装目标;CI 在 Ubuntu 和 macOS 上使用 Go 1.24 运行测试、race、覆盖率、lint 和安全扫描;release workflow 在 tag push 时构建 Linux、macOS、Windows 产物并生成 checksums。证据:`Makefile`、`.github/workflows/ci.yml`、`.github/workflows/release.yml`、`RELEASE.md`。
Makefile 提供构建、测试、覆盖率、lint、跨平台编译和安装目标;CI 在 Ubuntu 和 macOS 上使用 Go 1.24 运行测试、race、覆盖率、lint 和安全扫描;release workflow 在 tag push 时构建 Linux、macOS、Windows 产物并生成 checksums,并在配置 `HOMEBREW_TAP_TOKEN` 后自动渲染、推送 Homebrew tap formula(`talkincode/homebrew-tap`)。证据:`Makefile`、`.github/workflows/ci.yml`、`.github/workflows/release.yml`、`RELEASE.md`。

## 非目标(铁律)

Expand Down
Loading